Home | History | Annotate | Download | only in aidl
      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