blob: b8a48033ede5f310445f288e7e5e7cc7aac2776c [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001
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
32using namespace std;
33
34static void
35test_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// ==========================================================
76int
77convert_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// ==========================================================
92struct 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
101document_item_type* g_document = NULL;
102import_info* g_imports = NULL;
103
104static void
105main_document_parsed(document_item_type* d)
106{
107 g_document = d;
108}
109
110static void
111main_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
124static ParserCallbacks g_mainCallbacks = {
125 &main_document_parsed,
126 &main_import_parsed
127};
128
129char*
130parse_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// ==========================================================
158static void
159import_import_parsed(buffer_type* statement)
160{
161}
162
163static ParserCallbacks g_importCallbacks = {
164 &main_document_parsed,
165 &import_import_parsed
166};
167
168// ==========================================================
169static int
170check_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
247static int
248check_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// ==========================================================
272static const char*
273kind_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
286static char*
287rfind(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
299static int
300gather_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// ==========================================================
386static bool
387matches_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
410static int
411check_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
540next:
541 index++;
542 arg = arg->next;
543 }
544
545 return err;
546}
547
548static int
549check_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// ==========================================================
588static int
589exactly_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// ==========================================================
632void
633generate_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// ==========================================================
690static string
691generate_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// ==========================================================
722static string
723generate_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// ==========================================================
743static void
744check_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// ==========================================================
762static int
763parse_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
866static int
867check_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// ==========================================================
933static int
934compile_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
1063static int
1064preprocess_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// ==========================================================
1137int
1138main(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}