1 #include "aidl_language.h" 2 3 #include <iostream> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <string> 8 9 #include <android-base/strings.h> 10 11 #include "aidl_language_y.h" 12 #include "logging.h" 13 14 #ifdef _WIN32 15 int isatty(int fd) 16 { 17 return (fd == 0); 18 } 19 #endif 20 21 using android::aidl::IoDelegate; 22 using android::base::Join; 23 using android::base::Split; 24 using std::cerr; 25 using std::endl; 26 using std::string; 27 using std::unique_ptr; 28 29 void yylex_init(void **); 30 void yylex_destroy(void *); 31 void yyset_in(FILE *f, void *); 32 int yyparse(Parser*); 33 YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *); 34 void yy_delete_buffer(YY_BUFFER_STATE, void *); 35 36 AidlToken::AidlToken(const std::string& text, const std::string& comments) 37 : text_(text), 38 comments_(comments) {} 39 40 AidlType::AidlType(const std::string& name, unsigned line, 41 const std::string& comments, bool is_array) 42 : name_(name), 43 line_(line), 44 is_array_(is_array), 45 comments_(comments) {} 46 47 string AidlType::ToString() const { 48 return name_ + (is_array_ ? "[]" : ""); 49 } 50 51 AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type, 52 std::string name, unsigned line) 53 : type_(type), 54 direction_(direction), 55 direction_specified_(true), 56 name_(name), 57 line_(line) {} 58 59 AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line) 60 : type_(type), 61 direction_(AidlArgument::IN_DIR), 62 direction_specified_(false), 63 name_(name), 64 line_(line) {} 65 66 string AidlArgument::ToString() const { 67 string ret; 68 69 if (direction_specified_) { 70 switch(direction_) { 71 case AidlArgument::IN_DIR: 72 ret += "in "; 73 break; 74 case AidlArgument::OUT_DIR: 75 ret += "out "; 76 break; 77 case AidlArgument::INOUT_DIR: 78 ret += "inout "; 79 break; 80 } 81 } 82 83 ret += type_->ToString(); 84 ret += " "; 85 ret += name_; 86 87 return ret; 88 } 89 90 AidlConstant::AidlConstant(std::string name, int32_t value) 91 : name_(name), 92 value_(value) {} 93 94 AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name, 95 std::vector<std::unique_ptr<AidlArgument>>* args, 96 unsigned line, const std::string& comments, int id) 97 : oneway_(oneway), 98 comments_(comments), 99 type_(type), 100 name_(name), 101 line_(line), 102 arguments_(std::move(*args)), 103 id_(id) { 104 has_id_ = true; 105 delete args; 106 for (const unique_ptr<AidlArgument>& a : arguments_) { 107 if (a->IsIn()) { in_arguments_.push_back(a.get()); } 108 if (a->IsOut()) { out_arguments_.push_back(a.get()); } 109 } 110 } 111 112 AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name, 113 std::vector<std::unique_ptr<AidlArgument>>* args, 114 unsigned line, const std::string& comments) 115 : AidlMethod(oneway, type, name, args, line, comments, 0) { 116 has_id_ = false; 117 } 118 119 Parser::Parser(const IoDelegate& io_delegate) 120 : io_delegate_(io_delegate) { 121 yylex_init(&scanner_); 122 } 123 124 AidlParcelable::AidlParcelable(AidlQualifiedName* name, unsigned line, 125 const std::vector<std::string>& package, 126 const std::string& cpp_header) 127 : name_(name), 128 line_(line), 129 package_(package), 130 cpp_header_(cpp_header) { 131 // Strip off quotation marks if we actually have a cpp header. 132 if (cpp_header_.length() >= 2) { 133 cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2); 134 } 135 } 136 137 std::string AidlParcelable::GetPackage() const { 138 return Join(package_, '.'); 139 } 140 141 std::string AidlParcelable::GetCanonicalName() const { 142 if (package_.empty()) { 143 return GetName(); 144 } 145 return GetPackage() + "." + GetName(); 146 } 147 148 AidlInterface::AidlInterface(const std::string& name, unsigned line, 149 const std::string& comments, bool oneway, 150 std::vector<std::unique_ptr<AidlMember>>* members, 151 const std::vector<std::string>& package) 152 : name_(name), 153 comments_(comments), 154 line_(line), 155 oneway_(oneway), 156 package_(package) { 157 for (auto& member : *members) { 158 AidlMember* local = member.release(); 159 AidlMethod* method = local->AsMethod(); 160 AidlConstant* constant = local->AsConstant(); 161 162 if (method) { 163 methods_.emplace_back(method); 164 } else if (constant) { 165 constants_.emplace_back(constant); 166 } else { 167 LOG(FATAL) << "Member is neither method nor constant!"; 168 } 169 } 170 171 delete members; 172 } 173 174 std::string AidlInterface::GetPackage() const { 175 return Join(package_, '.'); 176 } 177 178 std::string AidlInterface::GetCanonicalName() const { 179 if (package_.empty()) { 180 return GetName(); 181 } 182 return GetPackage() + "." + GetName(); 183 } 184 185 AidlDocument::AidlDocument(AidlInterface* interface) 186 : interface_(interface) {} 187 188 AidlQualifiedName::AidlQualifiedName(std::string term, 189 std::string comments) 190 : terms_({term}), 191 comments_(comments) { 192 if (term.find('.') != string::npos) { 193 terms_ = Split(term, "."); 194 for (const auto& term: terms_) { 195 if (term.empty()) { 196 LOG(FATAL) << "Malformed qualified identifier: '" << term << "'"; 197 } 198 } 199 } 200 } 201 202 void AidlQualifiedName::AddTerm(std::string term) { 203 terms_.push_back(term); 204 } 205 206 AidlImport::AidlImport(const std::string& from, 207 const std::string& needed_class, unsigned line) 208 : from_(from), 209 needed_class_(needed_class), 210 line_(line) {} 211 212 Parser::~Parser() { 213 if (raw_buffer_) { 214 yy_delete_buffer(buffer_, scanner_); 215 raw_buffer_.reset(); 216 } 217 yylex_destroy(scanner_); 218 } 219 220 bool Parser::ParseFile(const string& filename) { 221 // Make sure we can read the file first, before trashing previous state. 222 unique_ptr<string> new_buffer = io_delegate_.GetFileContents(filename); 223 if (!new_buffer) { 224 LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'"; 225 return false; 226 } 227 228 // Throw away old parsing state if we have any. 229 if (raw_buffer_) { 230 yy_delete_buffer(buffer_, scanner_); 231 raw_buffer_.reset(); 232 } 233 234 raw_buffer_ = std::move(new_buffer); 235 // We're going to scan this buffer in place, and yacc demands we put two 236 // nulls at the end. 237 raw_buffer_->append(2u, '\0'); 238 filename_ = filename; 239 package_.reset(); 240 error_ = 0; 241 document_.reset(); 242 243 buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_); 244 245 if (yy::parser(this).parse() != 0 || error_ != 0) { 246 return false;} 247 248 if (document_.get() != nullptr) 249 return true; 250 251 LOG(ERROR) << "Parser succeeded but yielded no document!"; 252 return false; 253 } 254 255 void Parser::ReportError(const string& err, unsigned line) { 256 cerr << filename_ << ":" << line << ": " << err << endl; 257 error_ = 1; 258 } 259 260 std::vector<std::string> Parser::Package() const { 261 if (!package_) { 262 return {}; 263 } 264 return package_->GetTerms(); 265 } 266 267 void Parser::AddImport(AidlQualifiedName* name, unsigned line) { 268 imports_.emplace_back(new AidlImport(this->FileName(), 269 name->GetDotName(), line)); 270 delete name; 271 } 272