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