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