blob: 0df9f065381a61da4337dcd6ba6f7af3328131b1 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001
2#include "aidl_language.h"
3#include "options.h"
Elliott Hughes9ec96f92015-07-29 14:35:18 -07004#include "os.h"
Adam Lesinski282e1812014-01-23 18:17:42 -08005#include "search_path.h"
6#include "Type.h"
7#include "generate_java.h"
8#include <unistd.h>
9#include <fcntl.h>
10#include <sys/param.h>
11#include <sys/stat.h>
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <map>
17
Elliott Hughese17788c2015-08-17 12:41:46 -070018#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -080019#include <io.h>
Andrew Hsiehc9d32392014-05-07 20:14:30 +080020#include <direct.h>
Adam Lesinski282e1812014-01-23 18:17:42 -080021#include <sys/stat.h>
22#endif
23
24#ifndef O_BINARY
25# define O_BINARY 0
26#endif
27
28// The following are gotten as the offset from the allowable id's between
29// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
30// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
31#define MIN_USER_SET_METHOD_ID 0
32#define MAX_USER_SET_METHOD_ID 16777214
33
Christopher Wiley1eaa9ed2015-08-24 14:07:32 -070034using std::map;
35using std::set;
36using std::string;
37using std::vector;
Adam Lesinski282e1812014-01-23 18:17:42 -080038
39static void
40test_document(document_item_type* d)
41{
42 while (d) {
43 if (d->item_type == INTERFACE_TYPE_BINDER) {
44 interface_type* c = (interface_type*)d;
45 printf("interface %s %s {\n", c->package, c->name.data);
46 interface_item_type *q = (interface_item_type*)c->interface_items;
47 while (q) {
48 if (q->item_type == METHOD_TYPE) {
49 method_type *m = (method_type*)q;
50 printf(" %s %s(", m->type.type.data, m->name.data);
51 arg_type *p = m->args;
52 while (p) {
53 printf("%s %s",p->type.type.data,p->name.data);
54 if (p->next) printf(", ");
55 p=p->next;
56 }
57 printf(")");
58 printf(";\n");
59 }
60 q=q->next;
61 }
62 printf("}\n");
63 }
64 else if (d->item_type == USER_DATA_TYPE) {
65 user_data_type* b = (user_data_type*)d;
66 if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
67 printf("parcelable %s %s;\n", b->package, b->name.data);
68 }
69 if ((b->flattening_methods & RPC_DATA) != 0) {
70 printf("flattenable %s %s;\n", b->package, b->name.data);
71 }
72 }
73 else {
74 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
75 }
76 d = d->next;
77 }
78}
79
80// ==========================================================
81int
82convert_direction(const char* direction)
83{
84 if (direction == NULL) {
85 return IN_PARAMETER;
86 }
87 if (0 == strcmp(direction, "in")) {
88 return IN_PARAMETER;
89 }
90 if (0 == strcmp(direction, "out")) {
91 return OUT_PARAMETER;
92 }
93 return INOUT_PARAMETER;
94}
95
96// ==========================================================
97struct import_info {
98 const char* from;
99 const char* filename;
100 buffer_type statement;
101 const char* neededClass;
102 document_item_type* doc;
103 struct import_info* next;
104};
105
106document_item_type* g_document = NULL;
107import_info* g_imports = NULL;
108
109static void
110main_document_parsed(document_item_type* d)
111{
112 g_document = d;
113}
114
115static void
116main_import_parsed(buffer_type* statement)
117{
118 import_info* import = (import_info*)malloc(sizeof(import_info));
119 memset(import, 0, sizeof(import_info));
120 import->from = strdup(g_currentFilename);
121 import->statement.lineno = statement->lineno;
122 import->statement.data = strdup(statement->data);
123 import->statement.extra = NULL;
124 import->next = g_imports;
125 import->neededClass = parse_import_statement(statement->data);
126 g_imports = import;
127}
128
129static ParserCallbacks g_mainCallbacks = {
130 &main_document_parsed,
131 &main_import_parsed
132};
133
134char*
135parse_import_statement(const char* text)
136{
137 const char* end;
138 int len;
139
140 while (isspace(*text)) {
141 text++;
142 }
143 while (!isspace(*text)) {
144 text++;
145 }
146 while (isspace(*text)) {
147 text++;
148 }
149 end = text;
150 while (!isspace(*end) && *end != ';') {
151 end++;
152 }
153 len = end-text;
154
155 char* rv = (char*)malloc(len+1);
156 memcpy(rv, text, len);
157 rv[len] = '\0';
158
159 return rv;
160}
161
162// ==========================================================
163static void
164import_import_parsed(buffer_type* statement)
165{
166}
167
Adam Lesinski282e1812014-01-23 18:17:42 -0800168// ==========================================================
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
Elliott Hughes98c11b52015-07-29 08:44:17 -0700179#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800180 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
Elliott Hughes98c11b52015-07-29 08:44:17 -0700219#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800220 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
Yabin Cuifb8e2b12014-11-10 15:01:43 -0800230 // aidl assumes case-insensitivity on Mac Os and Windows.
231#if defined(__linux__)
Adam Lesinski282e1812014-01-23 18:17:42 -0800232 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
Ying Wang50fb02d2015-07-22 17:42:35 -0700677 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
678 // has been deleted, moved or renamed in incremental build.
679 fprintf(to, "%s :\n", options.inputFileName.c_str());
680
Adam Lesinski282e1812014-01-23 18:17:42 -0800681 // Output "<imported_file>: " so make won't fail if the imported file has
682 // been deleted, moved or renamed in incremental build.
683 import = g_imports;
684 while (import) {
685 if (import->filename) {
686 fprintf(to, "%s :\n", import->filename);
687 }
688 import = import->next;
689 }
690
691 fclose(to);
692}
693
694// ==========================================================
695static string
696generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
697{
698 string result;
699
700 // create the path to the destination folder based on the
701 // interface package name
702 result = options.outputBaseFolder;
703 result += OS_PATH_SEPARATOR;
704
705 string packageStr = package;
706 size_t len = packageStr.length();
707 for (size_t i=0; i<len; i++) {
708 if (packageStr[i] == '.') {
709 packageStr[i] = OS_PATH_SEPARATOR;
710 }
711 }
712
713 result += packageStr;
714
715 // add the filename by replacing the .aidl extension to .java
716 const char* p = strchr(name.data, '.');
717 len = p ? p-name.data : strlen(name.data);
718
719 result += OS_PATH_SEPARATOR;
720 result.append(name.data, len);
721 result += ".java";
722
723 return result;
724}
725
726// ==========================================================
727static string
728generate_outputFileName(const Options& options, const document_item_type* items)
729{
730 // items has already been checked to have only one interface.
731 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
732 interface_type* type = (interface_type*)items;
733
734 return generate_outputFileName2(options, type->name, type->package);
735 } else if (items->item_type == USER_DATA_TYPE) {
736 user_data_type* type = (user_data_type*)items;
737 return generate_outputFileName2(options, type->name, type->package);
738 }
739
740 // I don't think we can come here, but safer than returning NULL.
741 string result;
742 return result;
743}
744
745
746
747// ==========================================================
748static void
749check_outputFilePath(const string& path) {
750 size_t len = path.length();
751 for (size_t i=0; i<len ; i++) {
752 if (path[i] == OS_PATH_SEPARATOR) {
753 string p = path.substr(0, i);
754 if (access(path.data(), F_OK) != 0) {
Elliott Hughese17788c2015-08-17 12:41:46 -0700755#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800756 _mkdir(p.data());
757#else
758 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
759#endif
760 }
761 }
762 }
763}
764
765
766// ==========================================================
767static int
768parse_preprocessed_file(const string& filename)
769{
770 int err;
771
772 FILE* f = fopen(filename.c_str(), "rb");
773 if (f == NULL) {
774 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
775 filename.c_str());
776 return 1;
777 }
778
779 int lineno = 1;
780 char line[1024];
781 char type[1024];
782 char fullname[1024];
783 while (fgets(line, sizeof(line), f)) {
784 // skip comments and empty lines
785 if (!line[0] || strncmp(line, "//", 2) == 0) {
786 continue;
787 }
788
789 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
790
791 char* packagename;
792 char* classname = rfind(fullname, '.');
793 if (classname != NULL) {
794 *classname = '\0';
795 classname++;
796 packagename = fullname;
797 } else {
798 classname = fullname;
799 packagename = NULL;
800 }
801
802 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
803 // type, packagename, classname);
804 document_item_type* doc;
805
806 if (0 == strcmp("parcelable", type)) {
807 user_data_type* parcl = (user_data_type*)malloc(
808 sizeof(user_data_type));
809 memset(parcl, 0, sizeof(user_data_type));
810 parcl->document_item.item_type = USER_DATA_TYPE;
811 parcl->keyword_token.lineno = lineno;
812 parcl->keyword_token.data = strdup(type);
813 parcl->package = packagename ? strdup(packagename) : NULL;
814 parcl->name.lineno = lineno;
815 parcl->name.data = strdup(classname);
816 parcl->semicolon_token.lineno = lineno;
817 parcl->semicolon_token.data = strdup(";");
818 parcl->flattening_methods = PARCELABLE_DATA;
819 doc = (document_item_type*)parcl;
820 }
821 else if (0 == strcmp("flattenable", type)) {
822 user_data_type* parcl = (user_data_type*)malloc(
823 sizeof(user_data_type));
824 memset(parcl, 0, sizeof(user_data_type));
825 parcl->document_item.item_type = USER_DATA_TYPE;
826 parcl->keyword_token.lineno = lineno;
827 parcl->keyword_token.data = strdup(type);
828 parcl->package = packagename ? strdup(packagename) : NULL;
829 parcl->name.lineno = lineno;
830 parcl->name.data = strdup(classname);
831 parcl->semicolon_token.lineno = lineno;
832 parcl->semicolon_token.data = strdup(";");
833 parcl->flattening_methods = RPC_DATA;
834 doc = (document_item_type*)parcl;
835 }
836 else if (0 == strcmp("interface", type)) {
837 interface_type* iface = (interface_type*)malloc(
838 sizeof(interface_type));
839 memset(iface, 0, sizeof(interface_type));
840 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
841 iface->interface_token.lineno = lineno;
842 iface->interface_token.data = strdup(type);
843 iface->package = packagename ? strdup(packagename) : NULL;
844 iface->name.lineno = lineno;
845 iface->name.data = strdup(classname);
846 iface->open_brace_token.lineno = lineno;
847 iface->open_brace_token.data = strdup("{");
848 iface->close_brace_token.lineno = lineno;
849 iface->close_brace_token.data = strdup("}");
850 doc = (document_item_type*)iface;
851 }
852 else {
853 fprintf(stderr, "%s:%d: bad type in line: %s\n",
854 filename.c_str(), lineno, line);
Elliott Hughesb30296b2013-10-29 15:25:52 -0700855 fclose(f);
Adam Lesinski282e1812014-01-23 18:17:42 -0800856 return 1;
857 }
858 err = gather_types(filename.c_str(), doc);
859 lineno++;
860 }
861
862 if (!feof(f)) {
863 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
864 filename.c_str(), lineno);
865 return 1;
866 }
867
868 fclose(f);
869 return 0;
870}
871
872static int
873check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
874{
875 // Check whether there are any methods with manually assigned id's and any that are not.
876 // Either all method id's must be manually assigned or all of them must not.
877 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
878 set<int> usedIds;
879 interface_item_type* item = first_item;
880 bool hasUnassignedIds = false;
881 bool hasAssignedIds = false;
882 while (item != NULL) {
883 if (item->item_type == METHOD_TYPE) {
884 method_type* method_item = (method_type*)item;
885 if (method_item->hasId) {
886 hasAssignedIds = true;
887 method_item->assigned_id = atoi(method_item->id.data);
888 // Ensure that the user set id is not duplicated.
889 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
890 // We found a duplicate id, so throw an error.
891 fprintf(stderr,
892 "%s:%d Found duplicate method id (%d) for method: %s\n",
893 filename, method_item->id.lineno,
894 method_item->assigned_id, method_item->name.data);
895 return 1;
896 }
897 // Ensure that the user set id is within the appropriate limits
898 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
899 method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
900 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
901 filename, method_item->id.lineno,
902 method_item->assigned_id, method_item->name.data);
903 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
904 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
905 return 1;
906 }
907 usedIds.insert(method_item->assigned_id);
908 } else {
909 hasUnassignedIds = true;
910 }
911 if (hasAssignedIds && hasUnassignedIds) {
912 fprintf(stderr,
913 "%s: You must either assign id's to all methods or to none of them.\n",
914 filename);
915 return 1;
916 }
917 }
918 item = item->next;
919 }
920
921 // In the case that all methods have unassigned id's, set a unique id for them.
922 if (hasUnassignedIds) {
923 int newId = 0;
924 item = first_item;
925 while (item != NULL) {
926 if (item->item_type == METHOD_TYPE) {
927 method_type* method_item = (method_type*)item;
928 method_item->assigned_id = newId++;
929 }
930 item = item->next;
931 }
932 }
933
934 // success
935 return 0;
936}
937
938// ==========================================================
939static int
940compile_aidl(Options& options)
941{
942 int err = 0, N;
943
944 set_import_paths(options.importPaths);
945
946 register_base_types();
947
948 // import the preprocessed file
949 N = options.preprocessedFiles.size();
950 for (int i=0; i<N; i++) {
951 const string& s = options.preprocessedFiles[i];
952 err |= parse_preprocessed_file(s);
953 }
954 if (err != 0) {
955 return err;
956 }
957
958 // parse the main file
959 g_callbacks = &g_mainCallbacks;
960 err = parse_aidl(options.inputFileName.c_str());
961 document_item_type* mainDoc = g_document;
962 g_document = NULL;
963
964 // parse the imports
965 g_callbacks = &g_mainCallbacks;
966 import_info* import = g_imports;
967 while (import) {
968 if (NAMES.Find(import->neededClass) == NULL) {
969 import->filename = find_import_file(import->neededClass);
970 if (!import->filename) {
971 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
972 import->from, import->statement.lineno,
973 import->neededClass);
974 err |= 1;
975 } else {
976 err |= parse_aidl(import->filename);
977 import->doc = g_document;
978 if (import->doc == NULL) {
979 err |= 1;
980 }
981 }
982 }
983 import = import->next;
984 }
985 // bail out now if parsing wasn't successful
986 if (err != 0 || mainDoc == NULL) {
987 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
988 return 1;
989 }
990
991 // complain about ones that aren't in the right files
992 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
993 import = g_imports;
994 while (import) {
995 err |= check_filenames(import->filename, import->doc);
996 import = import->next;
997 }
998
999 // gather the types that have been declared
1000 err |= gather_types(options.inputFileName.c_str(), mainDoc);
1001 import = g_imports;
1002 while (import) {
1003 err |= gather_types(import->filename, import->doc);
1004 import = import->next;
1005 }
1006
1007#if 0
1008 printf("---- main doc ----\n");
1009 test_document(mainDoc);
1010
1011 import = g_imports;
1012 while (import) {
1013 printf("---- import doc ----\n");
1014 test_document(import->doc);
1015 import = import->next;
1016 }
1017 NAMES.Dump();
1018#endif
1019
1020 // check the referenced types in mainDoc to make sure we've imported them
1021 err |= check_types(options.inputFileName.c_str(), mainDoc);
1022
1023 // finally, there really only needs to be one thing in mainDoc, and it
1024 // needs to be an interface.
1025 bool onlyParcelable = false;
1026 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
1027
1028 // If this includes an interface definition, then assign method ids and validate.
1029 if (!onlyParcelable) {
1030 err |= check_and_assign_method_ids(options.inputFileName.c_str(),
1031 ((interface_type*)mainDoc)->interface_items);
1032 }
1033
1034 // after this, there shouldn't be any more errors because of the
1035 // input.
1036 if (err != 0 || mainDoc == NULL) {
1037 return 1;
1038 }
1039
1040 // if needed, generate the outputFileName from the outputBaseFolder
1041 if (options.outputFileName.length() == 0 &&
1042 options.outputBaseFolder.length() > 0) {
1043 options.outputFileName = generate_outputFileName(options, mainDoc);
1044 }
1045
1046 // if we were asked to, generate a make dependency file
1047 // unless it's a parcelable *and* it's supposed to fail on parcelable
1048 if ((options.autoDepFile || options.depFileName != "") &&
1049 !(onlyParcelable && options.failOnParcelable)) {
1050 // make sure the folders of the output file all exists
1051 check_outputFilePath(options.outputFileName);
1052 generate_dep_file(options, mainDoc);
1053 }
1054
1055 // they didn't ask to fail on parcelables, so just exit quietly.
1056 if (onlyParcelable && !options.failOnParcelable) {
1057 return 0;
1058 }
1059
1060 // make sure the folders of the output file all exists
1061 check_outputFilePath(options.outputFileName);
1062
1063 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1064 (interface_type*)mainDoc);
1065
1066 return err;
1067}
1068
1069static int
1070preprocess_aidl(const Options& options)
1071{
1072 vector<string> lines;
1073 int err;
1074
1075 // read files
1076 int N = options.filesToPreprocess.size();
1077 for (int i=0; i<N; i++) {
1078 g_callbacks = &g_mainCallbacks;
1079 err = parse_aidl(options.filesToPreprocess[i].c_str());
1080 if (err != 0) {
1081 return err;
1082 }
1083 document_item_type* doc = g_document;
1084 string line;
1085 if (doc->item_type == USER_DATA_TYPE) {
1086 user_data_type* parcelable = (user_data_type*)doc;
1087 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
1088 line = "parcelable ";
1089 }
1090 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1091 line = "flattenable ";
1092 }
1093 if (parcelable->package) {
1094 line += parcelable->package;
1095 line += '.';
1096 }
1097 line += parcelable->name.data;
1098 } else {
1099 line = "interface ";
1100 interface_type* iface = (interface_type*)doc;
1101 if (iface->package) {
1102 line += iface->package;
1103 line += '.';
1104 }
1105 line += iface->name.data;
1106 }
1107 line += ";\n";
1108 lines.push_back(line);
1109 }
1110
1111 // write preprocessed file
1112 int fd = open( options.outputFileName.c_str(),
1113 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
Elliott Hughese17788c2015-08-17 12:41:46 -07001114#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -08001115 _S_IREAD|_S_IWRITE);
1116#else
1117 S_IRUSR|S_IWUSR|S_IRGRP);
1118#endif
1119 if (fd == -1) {
1120 fprintf(stderr, "aidl: could not open file for write: %s\n",
1121 options.outputFileName.c_str());
1122 return 1;
1123 }
1124
1125 N = lines.size();
1126 for (int i=0; i<N; i++) {
1127 const string& s = lines[i];
1128 int len = s.length();
1129 if (len != write(fd, s.c_str(), len)) {
1130 fprintf(stderr, "aidl: error writing to file %s\n",
1131 options.outputFileName.c_str());
1132 close(fd);
1133 unlink(options.outputFileName.c_str());
1134 return 1;
1135 }
1136 }
1137
1138 close(fd);
1139 return 0;
1140}
1141
1142// ==========================================================
1143int
1144main(int argc, const char **argv)
1145{
1146 Options options;
1147 int result = parse_options(argc, argv, &options);
1148 if (result) {
1149 return result;
1150 }
1151
1152 switch (options.task)
1153 {
1154 case COMPILE_AIDL:
1155 return compile_aidl(options);
1156 case PREPROCESS_AIDL:
1157 return preprocess_aidl(options);
1158 }
1159 fprintf(stderr, "aidl: internal error\n");
1160 return 1;
1161}