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