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