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
33using namespace std;
34
35static void
36test_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// ==========================================================
77int
78convert_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// ==========================================================
93struct 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
102document_item_type* g_document = NULL;
103import_info* g_imports = NULL;
104
105static void
106main_document_parsed(document_item_type* d)
107{
108    g_document = d;
109}
110
111static void
112main_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
125static ParserCallbacks g_mainCallbacks = {
126    &main_document_parsed,
127    &main_import_parsed
128};
129
130char*
131parse_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// ==========================================================
159static void
160import_import_parsed(buffer_type* statement)
161{
162}
163
164static ParserCallbacks g_importCallbacks = {
165    &main_document_parsed,
166    &import_import_parsed
167};
168
169// ==========================================================
170static int
171check_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
248static int
249check_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// ==========================================================
273static const char*
274kind_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
287static char*
288rfind(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
300static int
301gather_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// ==========================================================
387static bool
388matches_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
411static int
412check_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
541next:
542        index++;
543        arg = arg->next;
544    }
545
546    return err;
547}
548
549static int
550check_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// ==========================================================
589static int
590exactly_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// ==========================================================
633void
634generate_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// ==========================================================
691static string
692generate_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// ==========================================================
723static string
724generate_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// ==========================================================
744static void
745check_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// ==========================================================
763static int
764parse_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
868static int
869check_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// ==========================================================
935static int
936compile_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
1065static int
1066preprocess_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// ==========================================================
1139int
1140main(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