blob: 9c1867e14a8f8d7da79be3a0bb19225aad4a84c0 [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);
Elliott Hughesb30296b2013-10-29 15:25:52 -0700850 fclose(f);
Adam Lesinski282e1812014-01-23 18:17:42 -0800851 return 1;
852 }
853 err = gather_types(filename.c_str(), doc);
854 lineno++;
855 }
856
857 if (!feof(f)) {
858 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
859 filename.c_str(), lineno);
860 return 1;
861 }
862
863 fclose(f);
864 return 0;
865}
866
867static int
868check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
869{
870 // Check whether there are any methods with manually assigned id's and any that are not.
871 // Either all method id's must be manually assigned or all of them must not.
872 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
873 set<int> usedIds;
874 interface_item_type* item = first_item;
875 bool hasUnassignedIds = false;
876 bool hasAssignedIds = false;
877 while (item != NULL) {
878 if (item->item_type == METHOD_TYPE) {
879 method_type* method_item = (method_type*)item;
880 if (method_item->hasId) {
881 hasAssignedIds = true;
882 method_item->assigned_id = atoi(method_item->id.data);
883 // Ensure that the user set id is not duplicated.
884 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
885 // We found a duplicate id, so throw an error.
886 fprintf(stderr,
887 "%s:%d Found duplicate method id (%d) for method: %s\n",
888 filename, method_item->id.lineno,
889 method_item->assigned_id, method_item->name.data);
890 return 1;
891 }
892 // Ensure that the user set id is within the appropriate limits
893 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
894 method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
895 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
896 filename, method_item->id.lineno,
897 method_item->assigned_id, method_item->name.data);
898 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
899 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
900 return 1;
901 }
902 usedIds.insert(method_item->assigned_id);
903 } else {
904 hasUnassignedIds = true;
905 }
906 if (hasAssignedIds && hasUnassignedIds) {
907 fprintf(stderr,
908 "%s: You must either assign id's to all methods or to none of them.\n",
909 filename);
910 return 1;
911 }
912 }
913 item = item->next;
914 }
915
916 // In the case that all methods have unassigned id's, set a unique id for them.
917 if (hasUnassignedIds) {
918 int newId = 0;
919 item = first_item;
920 while (item != NULL) {
921 if (item->item_type == METHOD_TYPE) {
922 method_type* method_item = (method_type*)item;
923 method_item->assigned_id = newId++;
924 }
925 item = item->next;
926 }
927 }
928
929 // success
930 return 0;
931}
932
933// ==========================================================
934static int
935compile_aidl(Options& options)
936{
937 int err = 0, N;
938
939 set_import_paths(options.importPaths);
940
941 register_base_types();
942
943 // import the preprocessed file
944 N = options.preprocessedFiles.size();
945 for (int i=0; i<N; i++) {
946 const string& s = options.preprocessedFiles[i];
947 err |= parse_preprocessed_file(s);
948 }
949 if (err != 0) {
950 return err;
951 }
952
953 // parse the main file
954 g_callbacks = &g_mainCallbacks;
955 err = parse_aidl(options.inputFileName.c_str());
956 document_item_type* mainDoc = g_document;
957 g_document = NULL;
958
959 // parse the imports
960 g_callbacks = &g_mainCallbacks;
961 import_info* import = g_imports;
962 while (import) {
963 if (NAMES.Find(import->neededClass) == NULL) {
964 import->filename = find_import_file(import->neededClass);
965 if (!import->filename) {
966 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
967 import->from, import->statement.lineno,
968 import->neededClass);
969 err |= 1;
970 } else {
971 err |= parse_aidl(import->filename);
972 import->doc = g_document;
973 if (import->doc == NULL) {
974 err |= 1;
975 }
976 }
977 }
978 import = import->next;
979 }
980 // bail out now if parsing wasn't successful
981 if (err != 0 || mainDoc == NULL) {
982 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
983 return 1;
984 }
985
986 // complain about ones that aren't in the right files
987 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
988 import = g_imports;
989 while (import) {
990 err |= check_filenames(import->filename, import->doc);
991 import = import->next;
992 }
993
994 // gather the types that have been declared
995 err |= gather_types(options.inputFileName.c_str(), mainDoc);
996 import = g_imports;
997 while (import) {
998 err |= gather_types(import->filename, import->doc);
999 import = import->next;
1000 }
1001
1002#if 0
1003 printf("---- main doc ----\n");
1004 test_document(mainDoc);
1005
1006 import = g_imports;
1007 while (import) {
1008 printf("---- import doc ----\n");
1009 test_document(import->doc);
1010 import = import->next;
1011 }
1012 NAMES.Dump();
1013#endif
1014
1015 // check the referenced types in mainDoc to make sure we've imported them
1016 err |= check_types(options.inputFileName.c_str(), mainDoc);
1017
1018 // finally, there really only needs to be one thing in mainDoc, and it
1019 // needs to be an interface.
1020 bool onlyParcelable = false;
1021 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
1022
1023 // If this includes an interface definition, then assign method ids and validate.
1024 if (!onlyParcelable) {
1025 err |= check_and_assign_method_ids(options.inputFileName.c_str(),
1026 ((interface_type*)mainDoc)->interface_items);
1027 }
1028
1029 // after this, there shouldn't be any more errors because of the
1030 // input.
1031 if (err != 0 || mainDoc == NULL) {
1032 return 1;
1033 }
1034
1035 // if needed, generate the outputFileName from the outputBaseFolder
1036 if (options.outputFileName.length() == 0 &&
1037 options.outputBaseFolder.length() > 0) {
1038 options.outputFileName = generate_outputFileName(options, mainDoc);
1039 }
1040
1041 // if we were asked to, generate a make dependency file
1042 // unless it's a parcelable *and* it's supposed to fail on parcelable
1043 if ((options.autoDepFile || options.depFileName != "") &&
1044 !(onlyParcelable && options.failOnParcelable)) {
1045 // make sure the folders of the output file all exists
1046 check_outputFilePath(options.outputFileName);
1047 generate_dep_file(options, mainDoc);
1048 }
1049
1050 // they didn't ask to fail on parcelables, so just exit quietly.
1051 if (onlyParcelable && !options.failOnParcelable) {
1052 return 0;
1053 }
1054
1055 // make sure the folders of the output file all exists
1056 check_outputFilePath(options.outputFileName);
1057
1058 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1059 (interface_type*)mainDoc);
1060
1061 return err;
1062}
1063
1064static int
1065preprocess_aidl(const Options& options)
1066{
1067 vector<string> lines;
1068 int err;
1069
1070 // read files
1071 int N = options.filesToPreprocess.size();
1072 for (int i=0; i<N; i++) {
1073 g_callbacks = &g_mainCallbacks;
1074 err = parse_aidl(options.filesToPreprocess[i].c_str());
1075 if (err != 0) {
1076 return err;
1077 }
1078 document_item_type* doc = g_document;
1079 string line;
1080 if (doc->item_type == USER_DATA_TYPE) {
1081 user_data_type* parcelable = (user_data_type*)doc;
1082 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
1083 line = "parcelable ";
1084 }
1085 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1086 line = "flattenable ";
1087 }
1088 if (parcelable->package) {
1089 line += parcelable->package;
1090 line += '.';
1091 }
1092 line += parcelable->name.data;
1093 } else {
1094 line = "interface ";
1095 interface_type* iface = (interface_type*)doc;
1096 if (iface->package) {
1097 line += iface->package;
1098 line += '.';
1099 }
1100 line += iface->name.data;
1101 }
1102 line += ";\n";
1103 lines.push_back(line);
1104 }
1105
1106 // write preprocessed file
1107 int fd = open( options.outputFileName.c_str(),
1108 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
1109#ifdef HAVE_MS_C_RUNTIME
1110 _S_IREAD|_S_IWRITE);
1111#else
1112 S_IRUSR|S_IWUSR|S_IRGRP);
1113#endif
1114 if (fd == -1) {
1115 fprintf(stderr, "aidl: could not open file for write: %s\n",
1116 options.outputFileName.c_str());
1117 return 1;
1118 }
1119
1120 N = lines.size();
1121 for (int i=0; i<N; i++) {
1122 const string& s = lines[i];
1123 int len = s.length();
1124 if (len != write(fd, s.c_str(), len)) {
1125 fprintf(stderr, "aidl: error writing to file %s\n",
1126 options.outputFileName.c_str());
1127 close(fd);
1128 unlink(options.outputFileName.c_str());
1129 return 1;
1130 }
1131 }
1132
1133 close(fd);
1134 return 0;
1135}
1136
1137// ==========================================================
1138int
1139main(int argc, const char **argv)
1140{
1141 Options options;
1142 int result = parse_options(argc, argv, &options);
1143 if (result) {
1144 return result;
1145 }
1146
1147 switch (options.task)
1148 {
1149 case COMPILE_AIDL:
1150 return compile_aidl(options);
1151 case PREPROCESS_AIDL:
1152 return preprocess_aidl(options);
1153 }
1154 fprintf(stderr, "aidl: internal error\n");
1155 return 1;
1156}