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