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
isatty(int fd)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 
AidlToken(const std::string & text,const std::string & comments)36 AidlToken::AidlToken(const std::string& text, const std::string& comments)
37     : text_(text),
38       comments_(comments) {}
39 
AidlType(const std::string & name,unsigned line,const std::string & comments,bool is_array)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 
ToString() const47 string AidlType::ToString() const {
48   return name_ + (is_array_ ? "[]" : "");
49 }
50 
AidlArgument(AidlArgument::Direction direction,AidlType * type,std::string name,unsigned line)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 
AidlArgument(AidlType * type,std::string name,unsigned line)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 
ToString() const66 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 
AidlConstant(std::string name,int32_t value)90 AidlConstant::AidlConstant(std::string name, int32_t value)
91     : name_(name),
92       value_(value) {}
93 
AidlMethod(bool oneway,AidlType * type,std::string name,std::vector<std::unique_ptr<AidlArgument>> * args,unsigned line,const std::string & comments,int id)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 
AidlMethod(bool oneway,AidlType * type,std::string name,std::vector<std::unique_ptr<AidlArgument>> * args,unsigned line,const std::string & comments)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 
Parser(const IoDelegate & io_delegate)119 Parser::Parser(const IoDelegate& io_delegate)
120     : io_delegate_(io_delegate) {
121   yylex_init(&scanner_);
122 }
123 
AidlParcelable(AidlQualifiedName * name,unsigned line,const std::vector<std::string> & package,const std::string & cpp_header)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 
GetPackage() const137 std::string AidlParcelable::GetPackage() const {
138   return Join(package_, '.');
139 }
140 
GetCanonicalName() const141 std::string AidlParcelable::GetCanonicalName() const {
142   if (package_.empty()) {
143     return GetName();
144   }
145   return GetPackage() + "." + GetName();
146 }
147 
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)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 
GetPackage() const174 std::string AidlInterface::GetPackage() const {
175   return Join(package_, '.');
176 }
177 
GetCanonicalName() const178 std::string AidlInterface::GetCanonicalName() const {
179   if (package_.empty()) {
180     return GetName();
181   }
182   return GetPackage() + "." + GetName();
183 }
184 
AidlDocument(AidlInterface * interface)185 AidlDocument::AidlDocument(AidlInterface* interface)
186     : interface_(interface) {}
187 
AidlQualifiedName(std::string term,std::string comments)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 
AddTerm(std::string term)202 void AidlQualifiedName::AddTerm(std::string term) {
203   terms_.push_back(term);
204 }
205 
AidlImport(const std::string & from,const std::string & needed_class,unsigned line)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 
~Parser()212 Parser::~Parser() {
213   if (raw_buffer_) {
214     yy_delete_buffer(buffer_, scanner_);
215     raw_buffer_.reset();
216   }
217   yylex_destroy(scanner_);
218 }
219 
ParseFile(const string & filename)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 
ReportError(const string & err,unsigned line)255 void Parser::ReportError(const string& err, unsigned line) {
256   cerr << filename_ << ":" << line << ": " << err << endl;
257   error_ = 1;
258 }
259 
Package() const260 std::vector<std::string> Parser::Package() const {
261   if (!package_) {
262     return {};
263   }
264   return package_->GetTerms();
265 }
266 
AddImport(AidlQualifiedName * name,unsigned line)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