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