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     fclose(to);
    677 }
    678 
    679 // ==========================================================
    680 static string
    681 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
    682 {
    683     string result;
    684 
    685     // create the path to the destination folder based on the
    686     // interface package name
    687     result = options.outputBaseFolder;
    688     result += OS_PATH_SEPARATOR;
    689 
    690     string packageStr = package;
    691     size_t len = packageStr.length();
    692     for (size_t i=0; i<len; i++) {
    693         if (packageStr[i] == '.') {
    694             packageStr[i] = OS_PATH_SEPARATOR;
    695         }
    696     }
    697 
    698     result += packageStr;
    699 
    700     // add the filename by replacing the .aidl extension to .java
    701     const char* p = strchr(name.data, '.');
    702     len = p ? p-name.data : strlen(name.data);
    703 
    704     result += OS_PATH_SEPARATOR;
    705     result.append(name.data, len);
    706     result += ".java";
    707 
    708     return result;
    709 }
    710 
    711 // ==========================================================
    712 static string
    713 generate_outputFileName(const Options& options, const document_item_type* items)
    714 {
    715     // items has already been checked to have only one interface.
    716     if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
    717         interface_type* type = (interface_type*)items;
    718 
    719         return generate_outputFileName2(options, type->name, type->package);
    720     } else if (items->item_type == USER_DATA_TYPE) {
    721         user_data_type* type = (user_data_type*)items;
    722         return generate_outputFileName2(options, type->name, type->package);
    723     }
    724 
    725     // I don't think we can come here, but safer than returning NULL.
    726     string result;
    727     return result;
    728 }
    729 
    730 
    731 
    732 // ==========================================================
    733 static void
    734 check_outputFilePath(const string& path) {
    735     size_t len = path.length();
    736     for (size_t i=0; i<len ; i++) {
    737         if (path[i] == OS_PATH_SEPARATOR) {
    738             string p = path.substr(0, i);
    739             if (access(path.data(), F_OK) != 0) {
    740 #ifdef HAVE_MS_C_RUNTIME
    741                 _mkdir(p.data());
    742 #else
    743                 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
    744 #endif
    745             }
    746         }
    747     }
    748 }
    749 
    750 
    751 // ==========================================================
    752 static int
    753 parse_preprocessed_file(const string& filename)
    754 {
    755     int err;
    756 
    757     FILE* f = fopen(filename.c_str(), "rb");
    758     if (f == NULL) {
    759         fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
    760                 filename.c_str());
    761         return 1;
    762     }
    763 
    764     int lineno = 1;
    765     char line[1024];
    766     char type[1024];
    767     char fullname[1024];
    768     while (fgets(line, sizeof(line), f)) {
    769         // skip comments and empty lines
    770         if (!line[0] || strncmp(line, "//", 2) == 0) {
    771           continue;
    772         }
    773 
    774         sscanf(line, "%s %[^; \r\n\t];", type, fullname);
    775 
    776         char* packagename;
    777         char* classname = rfind(fullname, '.');
    778         if (classname != NULL) {
    779             *classname = '\0';
    780             classname++;
    781             packagename = fullname;
    782         } else {
    783             classname = fullname;
    784             packagename = NULL;
    785         }
    786 
    787         //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
    788         //        type, packagename, classname);
    789         document_item_type* doc;
    790 
    791         if (0 == strcmp("parcelable", type)) {
    792             user_data_type* parcl = (user_data_type*)malloc(
    793                     sizeof(user_data_type));
    794             memset(parcl, 0, sizeof(user_data_type));
    795             parcl->document_item.item_type = USER_DATA_TYPE;
    796             parcl->keyword_token.lineno = lineno;
    797             parcl->keyword_token.data = strdup(type);
    798             parcl->package = packagename ? strdup(packagename) : NULL;
    799             parcl->name.lineno = lineno;
    800             parcl->name.data = strdup(classname);
    801             parcl->semicolon_token.lineno = lineno;
    802             parcl->semicolon_token.data = strdup(";");
    803             parcl->flattening_methods = PARCELABLE_DATA;
    804             doc = (document_item_type*)parcl;
    805         }
    806         else if (0 == strcmp("flattenable", type)) {
    807             user_data_type* parcl = (user_data_type*)malloc(
    808                     sizeof(user_data_type));
    809             memset(parcl, 0, sizeof(user_data_type));
    810             parcl->document_item.item_type = USER_DATA_TYPE;
    811             parcl->keyword_token.lineno = lineno;
    812             parcl->keyword_token.data = strdup(type);
    813             parcl->package = packagename ? strdup(packagename) : NULL;
    814             parcl->name.lineno = lineno;
    815             parcl->name.data = strdup(classname);
    816             parcl->semicolon_token.lineno = lineno;
    817             parcl->semicolon_token.data = strdup(";");
    818             parcl->flattening_methods = RPC_DATA;
    819             doc = (document_item_type*)parcl;
    820         }
    821         else if (0 == strcmp("interface", type)) {
    822             interface_type* iface = (interface_type*)malloc(
    823                     sizeof(interface_type));
    824             memset(iface, 0, sizeof(interface_type));
    825             iface->document_item.item_type = INTERFACE_TYPE_BINDER;
    826             iface->interface_token.lineno = lineno;
    827             iface->interface_token.data = strdup(type);
    828             iface->package = packagename ? strdup(packagename) : NULL;
    829             iface->name.lineno = lineno;
    830             iface->name.data = strdup(classname);
    831             iface->open_brace_token.lineno = lineno;
    832             iface->open_brace_token.data = strdup("{");
    833             iface->close_brace_token.lineno = lineno;
    834             iface->close_brace_token.data = strdup("}");
    835             doc = (document_item_type*)iface;
    836         }
    837         else {
    838             fprintf(stderr, "%s:%d: bad type in line: %s\n",
    839                     filename.c_str(), lineno, line);
    840             return 1;
    841         }
    842         err = gather_types(filename.c_str(), doc);
    843         lineno++;
    844     }
    845 
    846     if (!feof(f)) {
    847         fprintf(stderr, "%s:%d: error reading file, line to long.\n",
    848                 filename.c_str(), lineno);
    849         return 1;
    850     }
    851 
    852     fclose(f);
    853     return 0;
    854 }
    855 
    856 static int
    857 check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
    858 {
    859     // Check whether there are any methods with manually assigned id's and any that are not.
    860     // Either all method id's must be manually assigned or all of them must not.
    861     // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
    862     set<int> usedIds;
    863     interface_item_type* item = first_item;
    864     bool hasUnassignedIds = false;
    865     bool hasAssignedIds = false;
    866     while (item != NULL) {
    867         if (item->item_type == METHOD_TYPE) {
    868             method_type* method_item = (method_type*)item;
    869             if (method_item->hasId) {
    870                 hasAssignedIds = true;
    871                 method_item->assigned_id = atoi(method_item->id.data);
    872                 // Ensure that the user set id is not duplicated.
    873                 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
    874                     // We found a duplicate id, so throw an error.
    875                     fprintf(stderr,
    876                             "%s:%d Found duplicate method id (%d) for method: %s\n",
    877                             filename, method_item->id.lineno,
    878                             method_item->assigned_id, method_item->name.data);
    879                     return 1;
    880                 }
    881                 // Ensure that the user set id is within the appropriate limits
    882                 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
    883                         method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
    884                     fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
    885                             filename, method_item->id.lineno,
    886                             method_item->assigned_id, method_item->name.data);
    887                     fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
    888                             MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
    889                     return 1;
    890                 }
    891                 usedIds.insert(method_item->assigned_id);
    892             } else {
    893                 hasUnassignedIds = true;
    894             }
    895             if (hasAssignedIds && hasUnassignedIds) {
    896                 fprintf(stderr,
    897                         "%s: You must either assign id's to all methods or to none of them.\n",
    898                         filename);
    899                 return 1;
    900             }
    901         }
    902         item = item->next;
    903     }
    904 
    905     // In the case that all methods have unassigned id's, set a unique id for them.
    906     if (hasUnassignedIds) {
    907         int newId = 0;
    908         item = first_item;
    909         while (item != NULL) {
    910             if (item->item_type == METHOD_TYPE) {
    911                 method_type* method_item = (method_type*)item;
    912                 method_item->assigned_id = newId++;
    913             }
    914             item = item->next;
    915         }
    916     }
    917 
    918     // success
    919     return 0;
    920 }
    921 
    922 // ==========================================================
    923 static int
    924 compile_aidl(Options& options)
    925 {
    926     int err = 0, N;
    927 
    928     set_import_paths(options.importPaths);
    929 
    930     register_base_types();
    931 
    932     // import the preprocessed file
    933     N = options.preprocessedFiles.size();
    934     for (int i=0; i<N; i++) {
    935         const string& s = options.preprocessedFiles[i];
    936         err |= parse_preprocessed_file(s);
    937     }
    938     if (err != 0) {
    939         return err;
    940     }
    941 
    942     // parse the main file
    943     g_callbacks = &g_mainCallbacks;
    944     err = parse_aidl(options.inputFileName.c_str());
    945     document_item_type* mainDoc = g_document;
    946     g_document = NULL;
    947 
    948     // parse the imports
    949     g_callbacks = &g_mainCallbacks;
    950     import_info* import = g_imports;
    951     while (import) {
    952         if (NAMES.Find(import->neededClass) == NULL) {
    953             import->filename = find_import_file(import->neededClass);
    954             if (!import->filename) {
    955                 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
    956                         import->from, import->statement.lineno,
    957                         import->neededClass);
    958                 err |= 1;
    959             } else {
    960                 err |= parse_aidl(import->filename);
    961                 import->doc = g_document;
    962                 if (import->doc == NULL) {
    963                     err |= 1;
    964                 }
    965             }
    966         }
    967         import = import->next;
    968     }
    969     // bail out now if parsing wasn't successful
    970     if (err != 0 || mainDoc == NULL) {
    971         //fprintf(stderr, "aidl: parsing failed, stopping.\n");
    972         return 1;
    973     }
    974 
    975     // complain about ones that aren't in the right files
    976     err |= check_filenames(options.inputFileName.c_str(), mainDoc);
    977     import = g_imports;
    978     while (import) {
    979         err |= check_filenames(import->filename, import->doc);
    980         import = import->next;
    981     }
    982 
    983     // gather the types that have been declared
    984     err |= gather_types(options.inputFileName.c_str(), mainDoc);
    985     import = g_imports;
    986     while (import) {
    987         err |= gather_types(import->filename, import->doc);
    988         import = import->next;
    989     }
    990 
    991 #if 0
    992     printf("---- main doc ----\n");
    993     test_document(mainDoc);
    994 
    995     import = g_imports;
    996     while (import) {
    997         printf("---- import doc ----\n");
    998         test_document(import->doc);
    999         import = import->next;
   1000     }
   1001     NAMES.Dump();
   1002 #endif
   1003 
   1004     // check the referenced types in mainDoc to make sure we've imported them
   1005     err |= check_types(options.inputFileName.c_str(), mainDoc);
   1006 
   1007     // finally, there really only needs to be one thing in mainDoc, and it
   1008     // needs to be an interface.
   1009     bool onlyParcelable = false;
   1010     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
   1011 
   1012     // If this includes an interface definition, then assign method ids and validate.
   1013     if (!onlyParcelable) {
   1014         err |= check_and_assign_method_ids(options.inputFileName.c_str(),
   1015                 ((interface_type*)mainDoc)->interface_items);
   1016     }
   1017 
   1018     // after this, there shouldn't be any more errors because of the
   1019     // input.
   1020     if (err != 0 || mainDoc == NULL) {
   1021         return 1;
   1022     }
   1023 
   1024     // if needed, generate the outputFileName from the outputBaseFolder
   1025     if (options.outputFileName.length() == 0 &&
   1026             options.outputBaseFolder.length() > 0) {
   1027         options.outputFileName = generate_outputFileName(options, mainDoc);
   1028     }
   1029 
   1030     // if we were asked to, generate a make dependency file
   1031     // unless it's a parcelable *and* it's supposed to fail on parcelable
   1032     if ((options.autoDepFile || options.depFileName != "") &&
   1033             !(onlyParcelable && options.failOnParcelable)) {
   1034         // make sure the folders of the output file all exists
   1035         check_outputFilePath(options.outputFileName);
   1036         generate_dep_file(options, mainDoc);
   1037     }
   1038 
   1039     // they didn't ask to fail on parcelables, so just exit quietly.
   1040     if (onlyParcelable && !options.failOnParcelable) {
   1041         return 0;
   1042     }
   1043 
   1044     // make sure the folders of the output file all exists
   1045     check_outputFilePath(options.outputFileName);
   1046 
   1047     err = generate_java(options.outputFileName, options.inputFileName.c_str(),
   1048                         (interface_type*)mainDoc);
   1049 
   1050     return err;
   1051 }
   1052 
   1053 static int
   1054 preprocess_aidl(const Options& options)
   1055 {
   1056     vector<string> lines;
   1057     int err;
   1058 
   1059     // read files
   1060     int N = options.filesToPreprocess.size();
   1061     for (int i=0; i<N; i++) {
   1062         g_callbacks = &g_mainCallbacks;
   1063         err = parse_aidl(options.filesToPreprocess[i].c_str());
   1064         if (err != 0) {
   1065             return err;
   1066         }
   1067         document_item_type* doc = g_document;
   1068         string line;
   1069         if (doc->item_type == USER_DATA_TYPE) {
   1070             user_data_type* parcelable = (user_data_type*)doc;
   1071             if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
   1072                 line = "parcelable ";
   1073             }
   1074             if ((parcelable->flattening_methods & RPC_DATA) != 0) {
   1075                 line = "flattenable ";
   1076             }
   1077             if (parcelable->package) {
   1078                 line += parcelable->package;
   1079                 line += '.';
   1080             }
   1081             line += parcelable->name.data;
   1082         } else {
   1083             line = "interface ";
   1084             interface_type* iface = (interface_type*)doc;
   1085             if (iface->package) {
   1086                 line += iface->package;
   1087                 line += '.';
   1088             }
   1089             line += iface->name.data;
   1090         }
   1091         line += ";\n";
   1092         lines.push_back(line);
   1093     }
   1094 
   1095     // write preprocessed file
   1096     int fd = open( options.outputFileName.c_str(),
   1097                    O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
   1098 #ifdef HAVE_MS_C_RUNTIME
   1099                    _S_IREAD|_S_IWRITE);
   1100 #else
   1101                    S_IRUSR|S_IWUSR|S_IRGRP);
   1102 #endif
   1103     if (fd == -1) {
   1104         fprintf(stderr, "aidl: could not open file for write: %s\n",
   1105                 options.outputFileName.c_str());
   1106         return 1;
   1107     }
   1108 
   1109     N = lines.size();
   1110     for (int i=0; i<N; i++) {
   1111         const string& s = lines[i];
   1112         int len = s.length();
   1113         if (len != write(fd, s.c_str(), len)) {
   1114             fprintf(stderr, "aidl: error writing to file %s\n",
   1115                 options.outputFileName.c_str());
   1116             close(fd);
   1117             unlink(options.outputFileName.c_str());
   1118             return 1;
   1119         }
   1120     }
   1121 
   1122     close(fd);
   1123     return 0;
   1124 }
   1125 
   1126 // ==========================================================
   1127 int
   1128 main(int argc, const char **argv)
   1129 {
   1130     Options options;
   1131     int result = parse_options(argc, argv, &options);
   1132     if (result) {
   1133         return result;
   1134     }
   1135 
   1136     switch (options.task)
   1137     {
   1138         case COMPILE_AIDL:
   1139             return compile_aidl(options);
   1140         case PREPROCESS_AIDL:
   1141             return preprocess_aidl(options);
   1142     }
   1143     fprintf(stderr, "aidl: internal error\n");
   1144     return 1;
   1145 }
   1146