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