Home | History | Annotate | Download | only in aidl
      1 
      2 #include "aidl_language.h"
      3 #include "options.h"
      4 #include "search_path.h"
      5 #include "Type.h"
      6 #include "generate_java.h"
      7 #include <unistd.h>
      8 #include <fcntl.h>
      9 #include <sys/param.h>
     10 #include <sys/stat.h>
     11 
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <map>
     16 
     17 #ifdef HAVE_MS_C_RUNTIME
     18 #include <io.h>
     19 #include <direct.h>
     20 #include <sys/stat.h>
     21 #endif
     22 
     23 #ifndef O_BINARY
     24 #  define O_BINARY  0
     25 #endif
     26 
     27 // The following are gotten as the offset from the allowable id's between
     28 // android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
     29 // android.os.IBinder.LAST_CALL_TRANSACTION=16777215
     30 #define MIN_USER_SET_METHOD_ID                0
     31 #define MAX_USER_SET_METHOD_ID                16777214
     32 
     33 using namespace std;
     34 
     35 static void
     36 test_document(document_item_type* d)
     37 {
     38     while (d) {
     39         if (d->item_type == INTERFACE_TYPE_BINDER) {
     40             interface_type* c = (interface_type*)d;
     41             printf("interface %s %s {\n", c->package, c->name.data);
     42             interface_item_type *q = (interface_item_type*)c->interface_items;
     43             while (q) {
     44                 if (q->item_type == METHOD_TYPE) {
     45                     method_type *m = (method_type*)q;
     46                     printf("  %s %s(", m->type.type.data, m->name.data);
     47                     arg_type *p = m->args;
     48                     while (p) {
     49                         printf("%s %s",p->type.type.data,p->name.data);
     50                         if (p->next) printf(", ");
     51                         p=p->next;
     52                     }
     53                     printf(")");
     54                     printf(";\n");
     55                 }
     56                 q=q->next;
     57             }
     58             printf("}\n");
     59         }
     60         else if (d->item_type == USER_DATA_TYPE) {
     61             user_data_type* b = (user_data_type*)d;
     62             if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
     63                 printf("parcelable %s %s;\n", b->package, b->name.data);
     64             }
     65             if ((b->flattening_methods & RPC_DATA) != 0) {
     66                 printf("flattenable %s %s;\n", b->package, b->name.data);
     67             }
     68         }
     69         else {
     70             printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
     71         }
     72         d = d->next;
     73     }
     74 }
     75 
     76 // ==========================================================
     77 int
     78 convert_direction(const char* direction)
     79 {
     80     if (direction == NULL) {
     81         return IN_PARAMETER;
     82     }
     83     if (0 == strcmp(direction, "in")) {
     84         return IN_PARAMETER;
     85     }
     86     if (0 == strcmp(direction, "out")) {
     87         return OUT_PARAMETER;
     88     }
     89     return INOUT_PARAMETER;
     90 }
     91 
     92 // ==========================================================
     93 struct import_info {
     94     const char* from;
     95     const char* filename;
     96     buffer_type statement;
     97     const char* neededClass;
     98     document_item_type* doc;
     99     struct import_info* next;
    100 };
    101 
    102 document_item_type* g_document = NULL;
    103 import_info* g_imports = NULL;
    104 
    105 static void
    106 main_document_parsed(document_item_type* d)
    107 {
    108     g_document = d;
    109 }
    110 
    111 static void
    112 main_import_parsed(buffer_type* statement)
    113 {
    114     import_info* import = (import_info*)malloc(sizeof(import_info));
    115     memset(import, 0, sizeof(import_info));
    116     import->from = strdup(g_currentFilename);
    117     import->statement.lineno = statement->lineno;
    118     import->statement.data = strdup(statement->data);
    119     import->statement.extra = NULL;
    120     import->next = g_imports;
    121     import->neededClass = parse_import_statement(statement->data);
    122     g_imports = import;
    123 }
    124 
    125 static ParserCallbacks g_mainCallbacks = {
    126     &main_document_parsed,
    127     &main_import_parsed
    128 };
    129 
    130 char*
    131 parse_import_statement(const char* text)
    132 {
    133     const char* end;
    134     int len;
    135 
    136     while (isspace(*text)) {
    137         text++;
    138     }
    139     while (!isspace(*text)) {
    140         text++;
    141     }
    142     while (isspace(*text)) {
    143         text++;
    144     }
    145     end = text;
    146     while (!isspace(*end) && *end != ';') {
    147         end++;
    148     }
    149     len = end-text;
    150 
    151     char* rv = (char*)malloc(len+1);
    152     memcpy(rv, text, len);
    153     rv[len] = '\0';
    154 
    155     return rv;
    156 }
    157 
    158 // ==========================================================
    159 static void
    160 import_import_parsed(buffer_type* statement)
    161 {
    162 }
    163 
    164 static ParserCallbacks g_importCallbacks = {
    165     &main_document_parsed,
    166     &import_import_parsed
    167 };
    168 
    169 // ==========================================================
    170 static int
    171 check_filename(const char* filename, const char* package, buffer_type* name)
    172 {
    173     const char* p;
    174     string expected;
    175     string fn;
    176     size_t len;
    177     char cwd[MAXPATHLEN];
    178     bool valid = false;
    179 
    180 #ifdef HAVE_WINDOWS_PATHS
    181     if (isalpha(filename[0]) && filename[1] == ':'
    182         && filename[2] == OS_PATH_SEPARATOR) {
    183 #else
    184     if (filename[0] == OS_PATH_SEPARATOR) {
    185 #endif
    186         fn = filename;
    187     } else {
    188         fn = getcwd(cwd, sizeof(cwd));
    189         len = fn.length();
    190         if (fn[len-1] != OS_PATH_SEPARATOR) {
    191             fn += OS_PATH_SEPARATOR;
    192         }
    193         fn += filename;
    194     }
    195 
    196     if (package) {
    197         expected = package;
    198         expected += '.';
    199     }
    200 
    201     len = expected.length();
    202     for (size_t i=0; i<len; i++) {
    203         if (expected[i] == '.') {
    204             expected[i] = OS_PATH_SEPARATOR;
    205         }
    206     }
    207 
    208     p = strchr(name->data, '.');
    209     len = p ? p-name->data : strlen(name->data);
    210     expected.append(name->data, len);
    211 
    212     expected += ".aidl";
    213 
    214     len = fn.length();
    215     valid = (len >= expected.length());
    216 
    217     if (valid) {
    218         p = fn.c_str() + (len - expected.length());
    219 
    220 #ifdef HAVE_WINDOWS_PATHS
    221         if (OS_PATH_SEPARATOR != '/') {
    222             // Input filename under cygwin most likely has / separators
    223             // whereas the expected string uses \\ separators. Adjust
    224             // them accordingly.
    225           for (char *c = const_cast<char *>(p); *c; ++c) {
    226                 if (*c == '/') *c = OS_PATH_SEPARATOR;
    227             }
    228         }
    229 #endif
    230 
    231         // aidl assumes case-insensitivity on Mac Os and Windows.
    232 #if defined(__linux__)
    233         valid = (expected == p);
    234 #else
    235         valid = !strcasecmp(expected.c_str(), p);
    236 #endif
    237     }
    238 
    239     if (!valid) {
    240         fprintf(stderr, "%s:%d interface %s should be declared in a file"
    241                 " called %s.\n",
    242                 filename, name->lineno, name->data, expected.c_str());
    243         return 1;
    244     }
    245 
    246     return 0;
    247 }
    248 
    249 static int
    250 check_filenames(const char* filename, document_item_type* items)
    251 {
    252     int err = 0;
    253     while (items) {
    254         if (items->item_type == USER_DATA_TYPE) {
    255             user_data_type* p = (user_data_type*)items;
    256             err |= check_filename(filename, p->package, &p->name);
    257         }
    258         else if (items->item_type == INTERFACE_TYPE_BINDER
    259                 || items->item_type == INTERFACE_TYPE_RPC) {
    260             interface_type* c = (interface_type*)items;
    261             err |= check_filename(filename, c->package, &c->name);
    262         }
    263         else {
    264             fprintf(stderr, "aidl: internal error unkown document type %d.\n",
    265                         items->item_type);
    266             return 1;
    267         }
    268         items = items->next;
    269     }
    270     return err;
    271 }
    272 
    273 // ==========================================================
    274 static const char*
    275 kind_to_string(int kind)
    276 {
    277     switch (kind)
    278     {
    279         case Type::INTERFACE:
    280             return "an interface";
    281         case Type::USERDATA:
    282             return "a user data";
    283         default:
    284             return "ERROR";
    285     }
    286 }
    287 
    288 static char*
    289 rfind(char* str, char c)
    290 {
    291     char* p = str + strlen(str) - 1;
    292     while (p >= str) {
    293         if (*p == c) {
    294             return p;
    295         }
    296         p--;
    297     }
    298     return NULL;
    299 }
    300 
    301 static int
    302 gather_types(const char* filename, document_item_type* items)
    303 {
    304     int err = 0;
    305     while (items) {
    306         Type* type;
    307         if (items->item_type == USER_DATA_TYPE) {
    308             user_data_type* p = (user_data_type*)items;
    309             type = new UserDataType(p->package ? p->package : "", p->name.data,
    310                     false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
    311                     ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
    312         }
    313         else if (items->item_type == INTERFACE_TYPE_BINDER
    314                 || items->item_type == INTERFACE_TYPE_RPC) {
    315             interface_type* c = (interface_type*)items;
    316             type = new InterfaceType(c->package ? c->package : "",
    317                             c->name.data, false, c->oneway,
    318                             filename, c->name.lineno);
    319         }
    320         else {
    321             fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
    322             return 1;
    323         }
    324 
    325         Type* old = NAMES.Find(type->QualifiedName());
    326         if (old == NULL) {
    327             NAMES.Add(type);
    328 
    329             if (items->item_type == INTERFACE_TYPE_BINDER) {
    330                 // for interfaces, also add the stub and proxy types, we don't
    331                 // bother checking these for duplicates, because the parser
    332                 // won't let us do it.
    333                 interface_type* c = (interface_type*)items;
    334 
    335                 string name = c->name.data;
    336                 name += ".Stub";
    337                 Type* stub = new Type(c->package ? c->package : "",
    338                                         name, Type::GENERATED, false, false, false,
    339                                         filename, c->name.lineno);
    340                 NAMES.Add(stub);
    341 
    342                 name = c->name.data;
    343                 name += ".Stub.Proxy";
    344                 Type* proxy = new Type(c->package ? c->package : "",
    345                                         name, Type::GENERATED, false, false, false,
    346                                         filename, c->name.lineno);
    347                 NAMES.Add(proxy);
    348             }
    349             else if (items->item_type == INTERFACE_TYPE_RPC) {
    350                 // for interfaces, also add the service base type, we don't
    351                 // bother checking these for duplicates, because the parser
    352                 // won't let us do it.
    353                 interface_type* c = (interface_type*)items;
    354 
    355                 string name = c->name.data;
    356                 name += ".ServiceBase";
    357                 Type* base = new Type(c->package ? c->package : "",
    358                                         name, Type::GENERATED, false, false, false,
    359                                         filename, c->name.lineno);
    360                 NAMES.Add(base);
    361             }
    362         } else {
    363             if (old->Kind() == Type::BUILT_IN) {
    364                 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
    365                             filename, type->DeclLine(),
    366                             type->QualifiedName().c_str());
    367                 err = 1;
    368             }
    369             else if (type->Kind() != old->Kind()) {
    370                 const char* oldKind = kind_to_string(old->Kind());
    371                 const char* newKind = kind_to_string(type->Kind());
    372 
    373                 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
    374                             filename, type->DeclLine(),
    375                             type->QualifiedName().c_str(), newKind);
    376                 fprintf(stderr, "%s:%d    previously defined here as %s.\n",
    377                             old->DeclFile().c_str(), old->DeclLine(), oldKind);
    378                 err = 1;
    379             }
    380         }
    381 
    382         items = items->next;
    383     }
    384     return err;
    385 }
    386 
    387 // ==========================================================
    388 static bool
    389 matches_keyword(const char* str)
    390 {
    391     static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
    392         "byte", "case", "catch", "char", "class", "const", "continue",
    393         "default", "do", "double", "else", "enum", "extends", "final",
    394         "finally", "float", "for", "goto", "if", "implements", "import",
    395         "instanceof", "int", "interface", "long", "native", "new", "package",
    396         "private", "protected", "public", "return", "short", "static",
    397         "strictfp", "super", "switch", "synchronized", "this", "throw",
    398         "throws", "transient", "try", "void", "volatile", "while",
    399         "true", "false", "null",
    400         NULL
    401     };
    402     const char** k = KEYWORDS;
    403     while (*k) {
    404         if (0 == strcmp(str, *k)) {
    405             return true;
    406         }
    407         k++;
    408     }
    409     return false;
    410 }
    411 
    412 static int
    413 check_method(const char* filename, int kind, method_type* m)
    414 {
    415     int err = 0;
    416 
    417     // return type
    418     Type* returnType = NAMES.Search(m->type.type.data);
    419     if (returnType == NULL) {
    420         fprintf(stderr, "%s:%d unknown return type %s\n", filename,
    421                     m->type.type.lineno, m->type.type.data);
    422         err = 1;
    423         return err;
    424     }
    425 
    426     if (returnType == EVENT_FAKE_TYPE) {
    427         if (kind != INTERFACE_TYPE_RPC) {
    428             fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
    429                     filename, m->type.type.lineno);
    430             err = 1;
    431         }
    432     } else {
    433         if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
    434                     : returnType->CanWriteToRpcData())) {
    435             fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
    436                         m->type.type.lineno, m->type.type.data);
    437             err = 1;
    438         }
    439     }
    440 
    441     if (m->type.dimension > 0 && !returnType->CanBeArray()) {
    442         fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
    443                 m->type.array_token.lineno, m->type.type.data,
    444                 m->type.array_token.data);
    445         err = 1;
    446     }
    447 
    448     if (m->type.dimension > 1) {
    449         fprintf(stderr, "%s:%d return type %s%s only one"
    450                 " dimensional arrays are supported\n", filename,
    451                 m->type.array_token.lineno, m->type.type.data,
    452                 m->type.array_token.data);
    453         err = 1;
    454     }
    455 
    456     int index = 1;
    457 
    458     arg_type* arg = m->args;
    459     while (arg) {
    460         Type* t = NAMES.Search(arg->type.type.data);
    461 
    462         // check the arg type
    463         if (t == NULL) {
    464             fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
    465                     filename, m->type.type.lineno, arg->name.data, index,
    466                     arg->type.type.data);
    467             err = 1;
    468             goto next;
    469         }
    470 
    471         if (t == EVENT_FAKE_TYPE) {
    472             fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
    473                     filename, m->type.type.lineno, arg->name.data, index,
    474                     arg->type.type.data);
    475             err = 1;
    476             goto next;
    477         }
    478 
    479         if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
    480             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
    481                         filename, m->type.type.lineno, index,
    482                         arg->type.type.data, arg->name.data);
    483             err = 1;
    484         }
    485 
    486         if (returnType == EVENT_FAKE_TYPE
    487                 && convert_direction(arg->direction.data) != IN_PARAMETER) {
    488             fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
    489                     filename, m->type.type.lineno, index,
    490                     arg->type.type.data, arg->name.data);
    491             err = 1;
    492             goto next;
    493         }
    494 
    495         if (arg->direction.data == NULL
    496                 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
    497             fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
    498                                 " parameter, so you must declare it as in,"
    499                                 " out or inout.\n",
    500                         filename, m->type.type.lineno, index,
    501                         arg->type.type.data, arg->name.data);
    502             err = 1;
    503         }
    504 
    505         if (convert_direction(arg->direction.data) != IN_PARAMETER
    506                 && !t->CanBeOutParameter()
    507                 && arg->type.dimension == 0) {
    508             fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
    509                             " parameter.\n",
    510                         filename, m->type.type.lineno, index,
    511                         arg->direction.data, arg->type.type.data,
    512                         arg->name.data);
    513             err = 1;
    514         }
    515 
    516         if (arg->type.dimension > 0 && !t->CanBeArray()) {
    517             fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
    518                     " array.\n", filename,
    519                     m->type.array_token.lineno, index, arg->direction.data,
    520                     arg->type.type.data, arg->type.array_token.data,
    521                     arg->name.data);
    522             err = 1;
    523         }
    524 
    525         if (arg->type.dimension > 1) {
    526             fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
    527                     " dimensional arrays are supported\n", filename,
    528                     m->type.array_token.lineno, index, arg->direction.data,
    529                     arg->type.type.data, arg->type.array_token.data,
    530                     arg->name.data);
    531             err = 1;
    532         }
    533 
    534         // check that the name doesn't match a keyword
    535         if (matches_keyword(arg->name.data)) {
    536             fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
    537                     " Java or aidl keyword\n",
    538                     filename, m->name.lineno, index, arg->name.data);
    539             err = 1;
    540         }
    541 
    542 next:
    543         index++;
    544         arg = arg->next;
    545     }
    546 
    547     return err;
    548 }
    549 
    550 static int
    551 check_types(const char* filename, document_item_type* items)
    552 {
    553     int err = 0;
    554     while (items) {
    555         // (nothing to check for USER_DATA_TYPE)
    556         if (items->item_type == INTERFACE_TYPE_BINDER
    557                 || items->item_type == INTERFACE_TYPE_RPC) {
    558             map<string,method_type*> methodNames;
    559             interface_type* c = (interface_type*)items;
    560 
    561             interface_item_type* member = c->interface_items;
    562             while (member) {
    563                 if (member->item_type == METHOD_TYPE) {
    564                     method_type* m = (method_type*)member;
    565 
    566                     err |= check_method(filename, items->item_type, m);
    567 
    568                     // prevent duplicate methods
    569                     if (methodNames.find(m->name.data) == methodNames.end()) {
    570                         methodNames[m->name.data] = m;
    571                     } else {
    572                         fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
    573                                 filename, m->name.lineno, m->name.data);
    574                         method_type* old = methodNames[m->name.data];
    575                         fprintf(stderr, "%s:%d    previously defined here.\n",
    576                                 filename, old->name.lineno);
    577                         err = 1;
    578                     }
    579                 }
    580                 member = member->next;
    581             }
    582         }
    583 
    584         items = items->next;
    585     }
    586     return err;
    587 }
    588 
    589 // ==========================================================
    590 static int
    591 exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
    592                       bool* onlyParcelable)
    593 {
    594     if (items == NULL) {
    595         fprintf(stderr, "%s: file does not contain any interfaces\n",
    596                             filename);
    597         return 1;
    598     }
    599 
    600     const document_item_type* next = items->next;
    601     // Allow parcelables to skip the "one-only" rule.
    602     if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
    603         int lineno = -1;
    604         if (next->item_type == INTERFACE_TYPE_BINDER) {
    605             lineno = ((interface_type*)next)->interface_token.lineno;
    606         }
    607         else if (next->item_type == INTERFACE_TYPE_RPC) {
    608             lineno = ((interface_type*)next)->interface_token.lineno;
    609         }
    610         fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
    611                             filename, lineno);
    612         return 1;
    613     }
    614 
    615     if (items->item_type == USER_DATA_TYPE) {
    616         *onlyParcelable = true;
    617         if (options.failOnParcelable) {
    618             fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
    619                             " parcelables or flattenables,\n", filename,
    620                             ((user_data_type*)items)->keyword_token.lineno);
    621             fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
    622                             "may not go in the Makefile.\n", filename,
    623                             ((user_data_type*)items)->keyword_token.lineno);
    624             return 1;
    625         }
    626     } else {
    627         *onlyParcelable = false;
    628     }
    629 
    630     return 0;
    631 }
    632 
    633 // ==========================================================
    634 void
    635 generate_dep_file(const Options& options, const document_item_type* items)
    636 {
    637     /* we open the file in binary mode to ensure that the same output is
    638      * generated on all platforms !!
    639      */
    640     FILE* to = NULL;
    641     if (options.autoDepFile) {
    642         string fileName = options.outputFileName + ".d";
    643         to = fopen(fileName.c_str(), "wb");
    644     } else {
    645         to = fopen(options.depFileName.c_str(), "wb");
    646     }
    647 
    648     if (to == NULL) {
    649         return;
    650     }
    651 
    652     const char* slash = "\\";
    653     import_info* import = g_imports;
    654     if (import == NULL) {
    655         slash = "";
    656     }
    657 
    658     if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
    659         fprintf(to, "%s: \\\n", options.outputFileName.c_str());
    660     } else {
    661         // parcelable: there's no output file.
    662         fprintf(to, " : \\\n");
    663     }
    664     fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
    665 
    666     while (import) {
    667         if (import->next == NULL) {
    668             slash = "";
    669         }
    670         if (import->filename) {
    671             fprintf(to, "  %s %s\n", import->filename, slash);
    672         }
    673         import = import->next;
    674     }
    675 
    676     fprintf(to, "\n");
    677 
    678     // Output "<imported_file>: " so make won't fail if the imported file has
    679     // been deleted, moved or renamed in incremental build.
    680     import = g_imports;
    681     while (import) {
    682         if (import->filename) {
    683             fprintf(to, "%s :\n", import->filename);
    684         }
    685         import = import->next;
    686     }
    687 
    688     fclose(to);
    689 }
    690 
    691 // ==========================================================
    692 static string
    693 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
    694 {
    695     string result;
    696 
    697     // create the path to the destination folder based on the
    698     // interface package name
    699     result = options.outputBaseFolder;
    700     result += OS_PATH_SEPARATOR;
    701 
    702     string packageStr = package;
    703     size_t len = packageStr.length();
    704     for (size_t i=0; i<len; i++) {
    705         if (packageStr[i] == '.') {
    706             packageStr[i] = OS_PATH_SEPARATOR;
    707         }
    708     }
    709 
    710     result += packageStr;
    711 
    712     // add the filename by replacing the .aidl extension to .java
    713     const char* p = strchr(name.data, '.');
    714     len = p ? p-name.data : strlen(name.data);
    715 
    716     result += OS_PATH_SEPARATOR;
    717     result.append(name.data, len);
    718     result += ".java";
    719 
    720     return result;
    721 }
    722 
    723 // ==========================================================
    724 static string
    725 generate_outputFileName(const Options& options, const document_item_type* items)
    726 {
    727     // items has already been checked to have only one interface.
    728     if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
    729         interface_type* type = (interface_type*)items;
    730 
    731         return generate_outputFileName2(options, type->name, type->package);
    732     } else if (items->item_type == USER_DATA_TYPE) {
    733         user_data_type* type = (user_data_type*)items;
    734         return generate_outputFileName2(options, type->name, type->package);
    735     }
    736 
    737     // I don't think we can come here, but safer than returning NULL.
    738     string result;
    739     return result;
    740 }
    741 
    742 
    743 
    744 // ==========================================================
    745 static void
    746 check_outputFilePath(const string& path) {
    747     size_t len = path.length();
    748     for (size_t i=0; i<len ; i++) {
    749         if (path[i] == OS_PATH_SEPARATOR) {
    750             string p = path.substr(0, i);
    751             if (access(path.data(), F_OK) != 0) {
    752 #ifdef HAVE_MS_C_RUNTIME
    753                 _mkdir(p.data());
    754 #else
    755                 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
    756 #endif
    757             }
    758         }
    759     }
    760 }
    761 
    762 
    763 // ==========================================================
    764 static int
    765 parse_preprocessed_file(const string& filename)
    766 {
    767     int err;
    768 
    769     FILE* f = fopen(filename.c_str(), "rb");
    770     if (f == NULL) {
    771         fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
    772                 filename.c_str());
    773         return 1;
    774     }
    775 
    776     int lineno = 1;
    777     char line[1024];
    778     char type[1024];
    779     char fullname[1024];
    780     while (fgets(line, sizeof(line), f)) {
    781         // skip comments and empty lines
    782         if (!line[0] || strncmp(line, "//", 2) == 0) {
    783           continue;
    784         }
    785 
    786         sscanf(line, "%s %[^; \r\n\t];", type, fullname);
    787 
    788         char* packagename;
    789         char* classname = rfind(fullname, '.');
    790         if (classname != NULL) {
    791             *classname = '\0';
    792             classname++;
    793             packagename = fullname;
    794         } else {
    795             classname = fullname;
    796             packagename = NULL;
    797         }
    798 
    799         //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
    800         //        type, packagename, classname);
    801         document_item_type* doc;
    802 
    803         if (0 == strcmp("parcelable", type)) {
    804             user_data_type* parcl = (user_data_type*)malloc(
    805                     sizeof(user_data_type));
    806             memset(parcl, 0, sizeof(user_data_type));
    807             parcl->document_item.item_type = USER_DATA_TYPE;
    808             parcl->keyword_token.lineno = lineno;
    809             parcl->keyword_token.data = strdup(type);
    810             parcl->package = packagename ? strdup(packagename) : NULL;
    811             parcl->name.lineno = lineno;
    812             parcl->name.data = strdup(classname);
    813             parcl->semicolon_token.lineno = lineno;
    814             parcl->semicolon_token.data = strdup(";");
    815             parcl->flattening_methods = PARCELABLE_DATA;
    816             doc = (document_item_type*)parcl;
    817         }
    818         else if (0 == strcmp("flattenable", type)) {
    819             user_data_type* parcl = (user_data_type*)malloc(
    820                     sizeof(user_data_type));
    821             memset(parcl, 0, sizeof(user_data_type));
    822             parcl->document_item.item_type = USER_DATA_TYPE;
    823             parcl->keyword_token.lineno = lineno;
    824             parcl->keyword_token.data = strdup(type);
    825             parcl->package = packagename ? strdup(packagename) : NULL;
    826             parcl->name.lineno = lineno;
    827             parcl->name.data = strdup(classname);
    828             parcl->semicolon_token.lineno = lineno;
    829             parcl->semicolon_token.data = strdup(";");
    830             parcl->flattening_methods = RPC_DATA;
    831             doc = (document_item_type*)parcl;
    832         }
    833         else if (0 == strcmp("interface", type)) {
    834             interface_type* iface = (interface_type*)malloc(
    835                     sizeof(interface_type));
    836             memset(iface, 0, sizeof(interface_type));
    837             iface->document_item.item_type = INTERFACE_TYPE_BINDER;
    838             iface->interface_token.lineno = lineno;
    839             iface->interface_token.data = strdup(type);
    840             iface->package = packagename ? strdup(packagename) : NULL;
    841             iface->name.lineno = lineno;
    842             iface->name.data = strdup(classname);
    843             iface->open_brace_token.lineno = lineno;
    844             iface->open_brace_token.data = strdup("{");
    845             iface->close_brace_token.lineno = lineno;
    846             iface->close_brace_token.data = strdup("}");
    847             doc = (document_item_type*)iface;
    848         }
    849         else {
    850             fprintf(stderr, "%s:%d: bad type in line: %s\n",
    851                     filename.c_str(), lineno, line);
    852             fclose(f);
    853             return 1;
    854         }
    855         err = gather_types(filename.c_str(), doc);
    856         lineno++;
    857     }
    858 
    859     if (!feof(f)) {
    860         fprintf(stderr, "%s:%d: error reading file, line to long.\n",
    861                 filename.c_str(), lineno);
    862         return 1;
    863     }
    864 
    865     fclose(f);
    866     return 0;
    867 }
    868 
    869 static int
    870 check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
    871 {
    872     // Check whether there are any methods with manually assigned id's and any that are not.
    873     // Either all method id's must be manually assigned or all of them must not.
    874     // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
    875     set<int> usedIds;
    876     interface_item_type* item = first_item;
    877     bool hasUnassignedIds = false;
    878     bool hasAssignedIds = false;
    879     while (item != NULL) {
    880         if (item->item_type == METHOD_TYPE) {
    881             method_type* method_item = (method_type*)item;
    882             if (method_item->hasId) {
    883                 hasAssignedIds = true;
    884                 method_item->assigned_id = atoi(method_item->id.data);
    885                 // Ensure that the user set id is not duplicated.
    886                 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
    887                     // We found a duplicate id, so throw an error.
    888                     fprintf(stderr,
    889                             "%s:%d Found duplicate method id (%d) for method: %s\n",
    890                             filename, method_item->id.lineno,
    891                             method_item->assigned_id, method_item->name.data);
    892                     return 1;
    893                 }
    894                 // Ensure that the user set id is within the appropriate limits
    895                 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
    896                         method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
    897                     fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
    898                             filename, method_item->id.lineno,
    899                             method_item->assigned_id, method_item->name.data);
    900                     fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
    901                             MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
    902                     return 1;
    903                 }
    904                 usedIds.insert(method_item->assigned_id);
    905             } else {
    906                 hasUnassignedIds = true;
    907             }
    908             if (hasAssignedIds && hasUnassignedIds) {
    909                 fprintf(stderr,
    910                         "%s: You must either assign id's to all methods or to none of them.\n",
    911                         filename);
    912                 return 1;
    913             }
    914         }
    915         item = item->next;
    916     }
    917 
    918     // In the case that all methods have unassigned id's, set a unique id for them.
    919     if (hasUnassignedIds) {
    920         int newId = 0;
    921         item = first_item;
    922         while (item != NULL) {
    923             if (item->item_type == METHOD_TYPE) {
    924                 method_type* method_item = (method_type*)item;
    925                 method_item->assigned_id = newId++;
    926             }
    927             item = item->next;
    928         }
    929     }
    930 
    931     // success
    932     return 0;
    933 }
    934 
    935 // ==========================================================
    936 static int
    937 compile_aidl(Options& options)
    938 {
    939     int err = 0, N;
    940 
    941     set_import_paths(options.importPaths);
    942 
    943     register_base_types();
    944 
    945     // import the preprocessed file
    946     N = options.preprocessedFiles.size();
    947     for (int i=0; i<N; i++) {
    948         const string& s = options.preprocessedFiles[i];
    949         err |= parse_preprocessed_file(s);
    950     }
    951     if (err != 0) {
    952         return err;
    953     }
    954 
    955     // parse the main file
    956     g_callbacks = &g_mainCallbacks;
    957     err = parse_aidl(options.inputFileName.c_str());
    958     document_item_type* mainDoc = g_document;
    959     g_document = NULL;
    960 
    961     // parse the imports
    962     g_callbacks = &g_mainCallbacks;
    963     import_info* import = g_imports;
    964     while (import) {
    965         if (NAMES.Find(import->neededClass) == NULL) {
    966             import->filename = find_import_file(import->neededClass);
    967             if (!import->filename) {
    968                 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
    969                         import->from, import->statement.lineno,
    970                         import->neededClass);
    971                 err |= 1;
    972             } else {
    973                 err |= parse_aidl(import->filename);
    974                 import->doc = g_document;
    975                 if (import->doc == NULL) {
    976                     err |= 1;
    977                 }
    978             }
    979         }
    980         import = import->next;
    981     }
    982     // bail out now if parsing wasn't successful
    983     if (err != 0 || mainDoc == NULL) {
    984         //fprintf(stderr, "aidl: parsing failed, stopping.\n");
    985         return 1;
    986     }
    987 
    988     // complain about ones that aren't in the right files
    989     err |= check_filenames(options.inputFileName.c_str(), mainDoc);
    990     import = g_imports;
    991     while (import) {
    992         err |= check_filenames(import->filename, import->doc);
    993         import = import->next;
    994     }
    995 
    996     // gather the types that have been declared
    997     err |= gather_types(options.inputFileName.c_str(), mainDoc);
    998     import = g_imports;
    999     while (import) {
   1000         err |= gather_types(import->filename, import->doc);
   1001         import = import->next;
   1002     }
   1003 
   1004 #if 0
   1005     printf("---- main doc ----\n");
   1006     test_document(mainDoc);
   1007 
   1008     import = g_imports;
   1009     while (import) {
   1010         printf("---- import doc ----\n");
   1011         test_document(import->doc);
   1012         import = import->next;
   1013     }
   1014     NAMES.Dump();
   1015 #endif
   1016 
   1017     // check the referenced types in mainDoc to make sure we've imported them
   1018     err |= check_types(options.inputFileName.c_str(), mainDoc);
   1019 
   1020     // finally, there really only needs to be one thing in mainDoc, and it
   1021     // needs to be an interface.
   1022     bool onlyParcelable = false;
   1023     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
   1024 
   1025     // If this includes an interface definition, then assign method ids and validate.
   1026     if (!onlyParcelable) {
   1027         err |= check_and_assign_method_ids(options.inputFileName.c_str(),
   1028                 ((interface_type*)mainDoc)->interface_items);
   1029     }
   1030 
   1031     // after this, there shouldn't be any more errors because of the
   1032     // input.
   1033     if (err != 0 || mainDoc == NULL) {
   1034         return 1;
   1035     }
   1036 
   1037     // if needed, generate the outputFileName from the outputBaseFolder
   1038     if (options.outputFileName.length() == 0 &&
   1039             options.outputBaseFolder.length() > 0) {
   1040         options.outputFileName = generate_outputFileName(options, mainDoc);
   1041     }
   1042 
   1043     // if we were asked to, generate a make dependency file
   1044     // unless it's a parcelable *and* it's supposed to fail on parcelable
   1045     if ((options.autoDepFile || options.depFileName != "") &&
   1046             !(onlyParcelable && options.failOnParcelable)) {
   1047         // make sure the folders of the output file all exists
   1048         check_outputFilePath(options.outputFileName);
   1049         generate_dep_file(options, mainDoc);
   1050     }
   1051 
   1052     // they didn't ask to fail on parcelables, so just exit quietly.
   1053     if (onlyParcelable && !options.failOnParcelable) {
   1054         return 0;
   1055     }
   1056 
   1057     // make sure the folders of the output file all exists
   1058     check_outputFilePath(options.outputFileName);
   1059 
   1060     err = generate_java(options.outputFileName, options.inputFileName.c_str(),
   1061                         (interface_type*)mainDoc);
   1062 
   1063     return err;
   1064 }
   1065 
   1066 static int
   1067 preprocess_aidl(const Options& options)
   1068 {
   1069     vector<string> lines;
   1070     int err;
   1071 
   1072     // read files
   1073     int N = options.filesToPreprocess.size();
   1074     for (int i=0; i<N; i++) {
   1075         g_callbacks = &g_mainCallbacks;
   1076         err = parse_aidl(options.filesToPreprocess[i].c_str());
   1077         if (err != 0) {
   1078             return err;
   1079         }
   1080         document_item_type* doc = g_document;
   1081         string line;
   1082         if (doc->item_type == USER_DATA_TYPE) {
   1083             user_data_type* parcelable = (user_data_type*)doc;
   1084             if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
   1085                 line = "parcelable ";
   1086             }
   1087             if ((parcelable->flattening_methods & RPC_DATA) != 0) {
   1088                 line = "flattenable ";
   1089             }
   1090             if (parcelable->package) {
   1091                 line += parcelable->package;
   1092                 line += '.';
   1093             }
   1094             line += parcelable->name.data;
   1095         } else {
   1096             line = "interface ";
   1097             interface_type* iface = (interface_type*)doc;
   1098             if (iface->package) {
   1099                 line += iface->package;
   1100                 line += '.';
   1101             }
   1102             line += iface->name.data;
   1103         }
   1104         line += ";\n";
   1105         lines.push_back(line);
   1106     }
   1107 
   1108     // write preprocessed file
   1109     int fd = open( options.outputFileName.c_str(),
   1110                    O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
   1111 #ifdef HAVE_MS_C_RUNTIME
   1112                    _S_IREAD|_S_IWRITE);
   1113 #else
   1114                    S_IRUSR|S_IWUSR|S_IRGRP);
   1115 #endif
   1116     if (fd == -1) {
   1117         fprintf(stderr, "aidl: could not open file for write: %s\n",
   1118                 options.outputFileName.c_str());
   1119         return 1;
   1120     }
   1121 
   1122     N = lines.size();
   1123     for (int i=0; i<N; i++) {
   1124         const string& s = lines[i];
   1125         int len = s.length();
   1126         if (len != write(fd, s.c_str(), len)) {
   1127             fprintf(stderr, "aidl: error writing to file %s\n",
   1128                 options.outputFileName.c_str());
   1129             close(fd);
   1130             unlink(options.outputFileName.c_str());
   1131             return 1;
   1132         }
   1133     }
   1134 
   1135     close(fd);
   1136     return 0;
   1137 }
   1138 
   1139 // ==========================================================
   1140 int
   1141 main(int argc, const char **argv)
   1142 {
   1143     Options options;
   1144     int result = parse_options(argc, argv, &options);
   1145     if (result) {
   1146         return result;
   1147     }
   1148 
   1149     switch (options.task)
   1150     {
   1151         case COMPILE_AIDL:
   1152             return compile_aidl(options);
   1153         case PREPROCESS_AIDL:
   1154             return preprocess_aidl(options);
   1155     }
   1156     fprintf(stderr, "aidl: internal error\n");
   1157     return 1;
   1158 }
   1159