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