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
isatty(int fd)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 
AidlToken(const std::string & text,const std::string & comments)37 AidlToken::AidlToken(const std::string& text, const std::string& comments)
38     : text_(text),
39       comments_(comments) {}
40 
AidlType(const std::string & name,unsigned line,const std::string & comments,bool is_array)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 
ToString() const48 string AidlType::ToString() const {
49   return name_ + (is_array_ ? "[]" : "");
50 }
51 
AidlArgument(AidlArgument::Direction direction,AidlType * type,std::string name,unsigned line)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 
AidlArgument(AidlType * type,std::string name,unsigned line)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 
ToString() const67 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 
AidlIntConstant(std::string name,int32_t value)91 AidlIntConstant::AidlIntConstant(std::string name, int32_t value)
92     : name_(name),
93       value_(value),
94       is_valid_(true) {}
95 
AidlIntConstant(std::string name,std::string value,unsigned line_number)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 
AidlStringConstant(std::string name,std::string value,unsigned line_number)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 
AidlMethod(bool oneway,AidlType * type,std::string name,std::vector<std::unique_ptr<AidlArgument>> * args,unsigned line,const std::string & comments,int id)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 
AidlMethod(bool oneway,AidlType * type,std::string name,std::vector<std::unique_ptr<AidlArgument>> * args,unsigned line,const std::string & comments)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 
Parser(const IoDelegate & io_delegate)157 Parser::Parser(const IoDelegate& io_delegate)
158     : io_delegate_(io_delegate) {
159   yylex_init(&scanner_);
160 }
161 
AidlParcelable(AidlQualifiedName * name,unsigned line,const std::vector<std::string> & package,const std::string & cpp_header)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 
GetPackage() const175 std::string AidlParcelable::GetPackage() const {
176   return Join(package_, '.');
177 }
178 
GetCanonicalName() const179 std::string AidlParcelable::GetCanonicalName() const {
180   if (package_.empty()) {
181     return GetName();
182   }
183   return GetPackage() + "." + GetName();
184 }
185 
AidlInterface(const std::string & name,unsigned line,const std::string & comments,bool oneway,std::vector<std::unique_ptr<AidlMember>> * members,const std::vector<std::string> & package)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 
GetPackage() const215 std::string AidlInterface::GetPackage() const {
216   return Join(package_, '.');
217 }
218 
GetCanonicalName() const219 std::string AidlInterface::GetCanonicalName() const {
220   if (package_.empty()) {
221     return GetName();
222   }
223   return GetPackage() + "." + GetName();
224 }
225 
AidlDocument(AidlInterface * interface)226 AidlDocument::AidlDocument(AidlInterface* interface)
227     : interface_(interface) {}
228 
AidlQualifiedName(std::string term,std::string comments)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 
AddTerm(const std::string & term)243 void AidlQualifiedName::AddTerm(const std::string& term) {
244   terms_.push_back(term);
245 }
246 
AidlImport(const std::string & from,const std::string & needed_class,unsigned line)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 
~Parser()253 Parser::~Parser() {
254   if (raw_buffer_) {
255     yy_delete_buffer(buffer_, scanner_);
256     raw_buffer_.reset();
257   }
258   yylex_destroy(scanner_);
259 }
260 
ParseFile(const string & filename)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 
ReportError(const string & err,unsigned line)296 void Parser::ReportError(const string& err, unsigned line) {
297   cerr << filename_ << ":" << line << ": " << err << endl;
298   error_ = 1;
299 }
300 
Package() const301 std::vector<std::string> Parser::Package() const {
302   if (!package_) {
303     return {};
304   }
305   return package_->GetTerms();
306 }
307 
AddImport(AidlQualifiedName * name,unsigned line)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