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
test_document(document_item_type * d)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
convert_direction(const char * direction)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
main_document_parsed(document_item_type * d)106 main_document_parsed(document_item_type* d)
107 {
108     g_document = d;
109 }
110 
111 static void
main_import_parsed(buffer_type * statement)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*
parse_import_statement(const char * text)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
import_import_parsed(buffer_type * statement)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
check_filename(const char * filename,const char * package,buffer_type * name)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