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