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