blob: 46c689970dc40377c227ea0eed64b15d22bcdebf [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;
Casey Dahlinca4543c2015-09-01 13:21:26 -070066 if (b->parcelable) {
Adam Lesinski282e1812014-01-23 18:17:42 -080067 printf("parcelable %s %s;\n", b->package, b->name.data);
68 }
Adam Lesinski282e1812014-01-23 18:17:42 -080069 }
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 }
Casey Dahlinca4543c2015-09-01 13:21:26 -0700254 else if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800255 interface_type* c = (interface_type*)items;
256 err |= check_filename(filename, c->package, &c->name);
257 }
258 else {
259 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
260 items->item_type);
261 return 1;
262 }
263 items = items->next;
264 }
265 return err;
266}
267
268// ==========================================================
269static const char*
270kind_to_string(int kind)
271{
272 switch (kind)
273 {
274 case Type::INTERFACE:
275 return "an interface";
276 case Type::USERDATA:
277 return "a user data";
278 default:
279 return "ERROR";
280 }
281}
282
283static char*
284rfind(char* str, char c)
285{
286 char* p = str + strlen(str) - 1;
287 while (p >= str) {
288 if (*p == c) {
289 return p;
290 }
291 p--;
292 }
293 return NULL;
294}
295
296static int
297gather_types(const char* filename, document_item_type* items)
298{
299 int err = 0;
300 while (items) {
301 Type* type;
302 if (items->item_type == USER_DATA_TYPE) {
303 user_data_type* p = (user_data_type*)items;
304 type = new UserDataType(p->package ? p->package : "", p->name.data,
Casey Dahlinca4543c2015-09-01 13:21:26 -0700305 false, p->parcelable, filename, p->name.lineno);
Adam Lesinski282e1812014-01-23 18:17:42 -0800306 }
Casey Dahlinca4543c2015-09-01 13:21:26 -0700307 else if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800308 interface_type* c = (interface_type*)items;
309 type = new InterfaceType(c->package ? c->package : "",
310 c->name.data, false, c->oneway,
311 filename, c->name.lineno);
312 }
313 else {
314 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
315 return 1;
316 }
317
318 Type* old = NAMES.Find(type->QualifiedName());
319 if (old == NULL) {
320 NAMES.Add(type);
321
322 if (items->item_type == INTERFACE_TYPE_BINDER) {
323 // for interfaces, also add the stub and proxy types, we don't
324 // bother checking these for duplicates, because the parser
325 // won't let us do it.
326 interface_type* c = (interface_type*)items;
327
328 string name = c->name.data;
329 name += ".Stub";
330 Type* stub = new Type(c->package ? c->package : "",
Casey Dahlinca4543c2015-09-01 13:21:26 -0700331 name, Type::GENERATED, false, false,
Adam Lesinski282e1812014-01-23 18:17:42 -0800332 filename, c->name.lineno);
333 NAMES.Add(stub);
334
335 name = c->name.data;
336 name += ".Stub.Proxy";
337 Type* proxy = new Type(c->package ? c->package : "",
Casey Dahlinca4543c2015-09-01 13:21:26 -0700338 name, Type::GENERATED, false, false,
Adam Lesinski282e1812014-01-23 18:17:42 -0800339 filename, c->name.lineno);
340 NAMES.Add(proxy);
341 }
Adam Lesinski282e1812014-01-23 18:17:42 -0800342 } else {
343 if (old->Kind() == Type::BUILT_IN) {
344 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
345 filename, type->DeclLine(),
346 type->QualifiedName().c_str());
347 err = 1;
348 }
349 else if (type->Kind() != old->Kind()) {
350 const char* oldKind = kind_to_string(old->Kind());
351 const char* newKind = kind_to_string(type->Kind());
352
353 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
354 filename, type->DeclLine(),
355 type->QualifiedName().c_str(), newKind);
356 fprintf(stderr, "%s:%d previously defined here as %s.\n",
357 old->DeclFile().c_str(), old->DeclLine(), oldKind);
358 err = 1;
359 }
360 }
361
362 items = items->next;
363 }
364 return err;
365}
366
367// ==========================================================
368static bool
369matches_keyword(const char* str)
370{
371 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
372 "byte", "case", "catch", "char", "class", "const", "continue",
373 "default", "do", "double", "else", "enum", "extends", "final",
374 "finally", "float", "for", "goto", "if", "implements", "import",
375 "instanceof", "int", "interface", "long", "native", "new", "package",
376 "private", "protected", "public", "return", "short", "static",
377 "strictfp", "super", "switch", "synchronized", "this", "throw",
378 "throws", "transient", "try", "void", "volatile", "while",
379 "true", "false", "null",
380 NULL
381 };
382 const char** k = KEYWORDS;
383 while (*k) {
384 if (0 == strcmp(str, *k)) {
385 return true;
386 }
387 k++;
388 }
389 return false;
390}
391
392static int
Casey Dahlinca4543c2015-09-01 13:21:26 -0700393check_method(const char* filename, method_type* m)
Adam Lesinski282e1812014-01-23 18:17:42 -0800394{
395 int err = 0;
396
397 // return type
398 Type* returnType = NAMES.Search(m->type.type.data);
399 if (returnType == NULL) {
400 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
401 m->type.type.lineno, m->type.type.data);
402 err = 1;
403 return err;
404 }
405
Casey Dahlinca4543c2015-09-01 13:21:26 -0700406 if (!returnType->CanWriteToParcel()) {
407 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
Adam Lesinski282e1812014-01-23 18:17:42 -0800408 m->type.type.lineno, m->type.type.data);
Casey Dahlinca4543c2015-09-01 13:21:26 -0700409 err = 1;
Adam Lesinski282e1812014-01-23 18:17:42 -0800410 }
411
412 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
413 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
414 m->type.array_token.lineno, m->type.type.data,
415 m->type.array_token.data);
416 err = 1;
417 }
418
419 if (m->type.dimension > 1) {
420 fprintf(stderr, "%s:%d return type %s%s only one"
421 " dimensional arrays are supported\n", filename,
422 m->type.array_token.lineno, m->type.type.data,
423 m->type.array_token.data);
424 err = 1;
425 }
426
427 int index = 1;
428
429 arg_type* arg = m->args;
430 while (arg) {
431 Type* t = NAMES.Search(arg->type.type.data);
432
433 // check the arg type
434 if (t == NULL) {
435 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
436 filename, m->type.type.lineno, arg->name.data, index,
437 arg->type.type.data);
438 err = 1;
439 goto next;
440 }
441
Casey Dahlinca4543c2015-09-01 13:21:26 -0700442 if (!t->CanWriteToParcel()) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800443 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
444 filename, m->type.type.lineno, index,
445 arg->type.type.data, arg->name.data);
446 err = 1;
447 }
448
Adam Lesinski282e1812014-01-23 18:17:42 -0800449 if (arg->direction.data == NULL
450 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
451 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
452 " parameter, so you must declare it as in,"
453 " out or inout.\n",
454 filename, m->type.type.lineno, index,
455 arg->type.type.data, arg->name.data);
456 err = 1;
457 }
458
459 if (convert_direction(arg->direction.data) != IN_PARAMETER
460 && !t->CanBeOutParameter()
461 && arg->type.dimension == 0) {
462 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
463 " parameter.\n",
464 filename, m->type.type.lineno, index,
465 arg->direction.data, arg->type.type.data,
466 arg->name.data);
467 err = 1;
468 }
469
470 if (arg->type.dimension > 0 && !t->CanBeArray()) {
471 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
472 " array.\n", filename,
473 m->type.array_token.lineno, index, arg->direction.data,
474 arg->type.type.data, arg->type.array_token.data,
475 arg->name.data);
476 err = 1;
477 }
478
479 if (arg->type.dimension > 1) {
480 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
481 " dimensional arrays are supported\n", filename,
482 m->type.array_token.lineno, index, arg->direction.data,
483 arg->type.type.data, arg->type.array_token.data,
484 arg->name.data);
485 err = 1;
486 }
487
488 // check that the name doesn't match a keyword
489 if (matches_keyword(arg->name.data)) {
490 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
491 " Java or aidl keyword\n",
492 filename, m->name.lineno, index, arg->name.data);
493 err = 1;
494 }
495
496next:
497 index++;
498 arg = arg->next;
499 }
500
501 return err;
502}
503
504static int
505check_types(const char* filename, document_item_type* items)
506{
507 int err = 0;
508 while (items) {
509 // (nothing to check for USER_DATA_TYPE)
Casey Dahlinca4543c2015-09-01 13:21:26 -0700510 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800511 map<string,method_type*> methodNames;
512 interface_type* c = (interface_type*)items;
513
514 interface_item_type* member = c->interface_items;
515 while (member) {
516 if (member->item_type == METHOD_TYPE) {
517 method_type* m = (method_type*)member;
518
Casey Dahlinca4543c2015-09-01 13:21:26 -0700519 err |= check_method(filename, m);
Adam Lesinski282e1812014-01-23 18:17:42 -0800520
521 // prevent duplicate methods
522 if (methodNames.find(m->name.data) == methodNames.end()) {
523 methodNames[m->name.data] = m;
524 } else {
525 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
526 filename, m->name.lineno, m->name.data);
527 method_type* old = methodNames[m->name.data];
528 fprintf(stderr, "%s:%d previously defined here.\n",
529 filename, old->name.lineno);
530 err = 1;
531 }
532 }
533 member = member->next;
534 }
535 }
536
537 items = items->next;
538 }
539 return err;
540}
541
542// ==========================================================
543static int
544exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
545 bool* onlyParcelable)
546{
547 if (items == NULL) {
548 fprintf(stderr, "%s: file does not contain any interfaces\n",
549 filename);
550 return 1;
551 }
552
553 const document_item_type* next = items->next;
554 // Allow parcelables to skip the "one-only" rule.
555 if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
556 int lineno = -1;
557 if (next->item_type == INTERFACE_TYPE_BINDER) {
558 lineno = ((interface_type*)next)->interface_token.lineno;
559 }
Adam Lesinski282e1812014-01-23 18:17:42 -0800560 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
561 filename, lineno);
562 return 1;
563 }
564
565 if (items->item_type == USER_DATA_TYPE) {
566 *onlyParcelable = true;
567 if (options.failOnParcelable) {
568 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
Casey Dahlinca4543c2015-09-01 13:21:26 -0700569 " parcelables,\n", filename,
Adam Lesinski282e1812014-01-23 18:17:42 -0800570 ((user_data_type*)items)->keyword_token.lineno);
Casey Dahlinca4543c2015-09-01 13:21:26 -0700571 fprintf(stderr, "%s:%d .aidl files that only declare parcelables"
Adam Lesinski282e1812014-01-23 18:17:42 -0800572 "may not go in the Makefile.\n", filename,
573 ((user_data_type*)items)->keyword_token.lineno);
574 return 1;
575 }
576 } else {
577 *onlyParcelable = false;
578 }
579
580 return 0;
581}
582
583// ==========================================================
584void
585generate_dep_file(const Options& options, const document_item_type* items)
586{
587 /* we open the file in binary mode to ensure that the same output is
588 * generated on all platforms !!
589 */
590 FILE* to = NULL;
591 if (options.autoDepFile) {
592 string fileName = options.outputFileName + ".d";
593 to = fopen(fileName.c_str(), "wb");
594 } else {
595 to = fopen(options.depFileName.c_str(), "wb");
596 }
597
598 if (to == NULL) {
599 return;
600 }
601
602 const char* slash = "\\";
603 import_info* import = g_imports;
604 if (import == NULL) {
605 slash = "";
606 }
607
Casey Dahlinca4543c2015-09-01 13:21:26 -0700608 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800609 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
610 } else {
611 // parcelable: there's no output file.
612 fprintf(to, " : \\\n");
613 }
614 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
615
616 while (import) {
617 if (import->next == NULL) {
618 slash = "";
619 }
620 if (import->filename) {
621 fprintf(to, " %s %s\n", import->filename, slash);
622 }
623 import = import->next;
624 }
625
626 fprintf(to, "\n");
627
Ying Wang50fb02d2015-07-22 17:42:35 -0700628 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
629 // has been deleted, moved or renamed in incremental build.
630 fprintf(to, "%s :\n", options.inputFileName.c_str());
631
Adam Lesinski282e1812014-01-23 18:17:42 -0800632 // Output "<imported_file>: " so make won't fail if the imported file has
633 // been deleted, moved or renamed in incremental build.
634 import = g_imports;
635 while (import) {
636 if (import->filename) {
637 fprintf(to, "%s :\n", import->filename);
638 }
639 import = import->next;
640 }
641
642 fclose(to);
643}
644
645// ==========================================================
646static string
647generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
648{
649 string result;
650
651 // create the path to the destination folder based on the
652 // interface package name
653 result = options.outputBaseFolder;
654 result += OS_PATH_SEPARATOR;
655
656 string packageStr = package;
657 size_t len = packageStr.length();
658 for (size_t i=0; i<len; i++) {
659 if (packageStr[i] == '.') {
660 packageStr[i] = OS_PATH_SEPARATOR;
661 }
662 }
663
664 result += packageStr;
665
666 // add the filename by replacing the .aidl extension to .java
667 const char* p = strchr(name.data, '.');
668 len = p ? p-name.data : strlen(name.data);
669
670 result += OS_PATH_SEPARATOR;
671 result.append(name.data, len);
672 result += ".java";
673
674 return result;
675}
676
677// ==========================================================
678static string
679generate_outputFileName(const Options& options, const document_item_type* items)
680{
681 // items has already been checked to have only one interface.
Casey Dahlinca4543c2015-09-01 13:21:26 -0700682 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinski282e1812014-01-23 18:17:42 -0800683 interface_type* type = (interface_type*)items;
684
685 return generate_outputFileName2(options, type->name, type->package);
686 } else if (items->item_type == USER_DATA_TYPE) {
687 user_data_type* type = (user_data_type*)items;
688 return generate_outputFileName2(options, type->name, type->package);
689 }
690
691 // I don't think we can come here, but safer than returning NULL.
692 string result;
693 return result;
694}
695
696
697
698// ==========================================================
699static void
700check_outputFilePath(const string& path) {
701 size_t len = path.length();
702 for (size_t i=0; i<len ; i++) {
703 if (path[i] == OS_PATH_SEPARATOR) {
704 string p = path.substr(0, i);
705 if (access(path.data(), F_OK) != 0) {
Elliott Hughese17788c2015-08-17 12:41:46 -0700706#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800707 _mkdir(p.data());
708#else
709 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
710#endif
711 }
712 }
713 }
714}
715
716
717// ==========================================================
718static int
719parse_preprocessed_file(const string& filename)
720{
721 int err;
722
723 FILE* f = fopen(filename.c_str(), "rb");
724 if (f == NULL) {
725 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
726 filename.c_str());
727 return 1;
728 }
729
730 int lineno = 1;
731 char line[1024];
732 char type[1024];
733 char fullname[1024];
734 while (fgets(line, sizeof(line), f)) {
735 // skip comments and empty lines
736 if (!line[0] || strncmp(line, "//", 2) == 0) {
737 continue;
738 }
739
740 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
741
742 char* packagename;
743 char* classname = rfind(fullname, '.');
744 if (classname != NULL) {
745 *classname = '\0';
746 classname++;
747 packagename = fullname;
748 } else {
749 classname = fullname;
750 packagename = NULL;
751 }
752
753 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
754 // type, packagename, classname);
755 document_item_type* doc;
756
757 if (0 == strcmp("parcelable", type)) {
758 user_data_type* parcl = (user_data_type*)malloc(
759 sizeof(user_data_type));
760 memset(parcl, 0, sizeof(user_data_type));
761 parcl->document_item.item_type = USER_DATA_TYPE;
762 parcl->keyword_token.lineno = lineno;
763 parcl->keyword_token.data = strdup(type);
764 parcl->package = packagename ? strdup(packagename) : NULL;
765 parcl->name.lineno = lineno;
766 parcl->name.data = strdup(classname);
767 parcl->semicolon_token.lineno = lineno;
768 parcl->semicolon_token.data = strdup(";");
Casey Dahlinca4543c2015-09-01 13:21:26 -0700769 parcl->parcelable = true;
Adam Lesinski282e1812014-01-23 18:17:42 -0800770 doc = (document_item_type*)parcl;
771 }
772 else if (0 == strcmp("interface", type)) {
773 interface_type* iface = (interface_type*)malloc(
774 sizeof(interface_type));
775 memset(iface, 0, sizeof(interface_type));
776 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
777 iface->interface_token.lineno = lineno;
778 iface->interface_token.data = strdup(type);
779 iface->package = packagename ? strdup(packagename) : NULL;
780 iface->name.lineno = lineno;
781 iface->name.data = strdup(classname);
782 iface->open_brace_token.lineno = lineno;
783 iface->open_brace_token.data = strdup("{");
784 iface->close_brace_token.lineno = lineno;
785 iface->close_brace_token.data = strdup("}");
786 doc = (document_item_type*)iface;
787 }
788 else {
789 fprintf(stderr, "%s:%d: bad type in line: %s\n",
790 filename.c_str(), lineno, line);
Elliott Hughesb30296b2013-10-29 15:25:52 -0700791 fclose(f);
Adam Lesinski282e1812014-01-23 18:17:42 -0800792 return 1;
793 }
794 err = gather_types(filename.c_str(), doc);
795 lineno++;
796 }
797
798 if (!feof(f)) {
799 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
800 filename.c_str(), lineno);
801 return 1;
802 }
803
804 fclose(f);
805 return 0;
806}
807
808static int
809check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
810{
811 // Check whether there are any methods with manually assigned id's and any that are not.
812 // Either all method id's must be manually assigned or all of them must not.
813 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
814 set<int> usedIds;
815 interface_item_type* item = first_item;
816 bool hasUnassignedIds = false;
817 bool hasAssignedIds = false;
818 while (item != NULL) {
819 if (item->item_type == METHOD_TYPE) {
820 method_type* method_item = (method_type*)item;
821 if (method_item->hasId) {
822 hasAssignedIds = true;
823 method_item->assigned_id = atoi(method_item->id.data);
824 // Ensure that the user set id is not duplicated.
825 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
826 // We found a duplicate id, so throw an error.
827 fprintf(stderr,
828 "%s:%d Found duplicate method id (%d) for method: %s\n",
829 filename, method_item->id.lineno,
830 method_item->assigned_id, method_item->name.data);
831 return 1;
832 }
833 // Ensure that the user set id is within the appropriate limits
834 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
835 method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
836 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
837 filename, method_item->id.lineno,
838 method_item->assigned_id, method_item->name.data);
839 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
840 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
841 return 1;
842 }
843 usedIds.insert(method_item->assigned_id);
844 } else {
845 hasUnassignedIds = true;
846 }
847 if (hasAssignedIds && hasUnassignedIds) {
848 fprintf(stderr,
849 "%s: You must either assign id's to all methods or to none of them.\n",
850 filename);
851 return 1;
852 }
853 }
854 item = item->next;
855 }
856
857 // In the case that all methods have unassigned id's, set a unique id for them.
858 if (hasUnassignedIds) {
859 int newId = 0;
860 item = first_item;
861 while (item != NULL) {
862 if (item->item_type == METHOD_TYPE) {
863 method_type* method_item = (method_type*)item;
864 method_item->assigned_id = newId++;
865 }
866 item = item->next;
867 }
868 }
869
870 // success
871 return 0;
872}
873
874// ==========================================================
Christopher Wiley2f774172015-08-30 10:57:07 -0700875int
Adam Lesinski282e1812014-01-23 18:17:42 -0800876compile_aidl(Options& options)
877{
878 int err = 0, N;
879
880 set_import_paths(options.importPaths);
881
882 register_base_types();
883
884 // import the preprocessed file
885 N = options.preprocessedFiles.size();
886 for (int i=0; i<N; i++) {
887 const string& s = options.preprocessedFiles[i];
888 err |= parse_preprocessed_file(s);
889 }
890 if (err != 0) {
891 return err;
892 }
893
894 // parse the main file
895 g_callbacks = &g_mainCallbacks;
896 err = parse_aidl(options.inputFileName.c_str());
897 document_item_type* mainDoc = g_document;
898 g_document = NULL;
899
900 // parse the imports
901 g_callbacks = &g_mainCallbacks;
902 import_info* import = g_imports;
903 while (import) {
904 if (NAMES.Find(import->neededClass) == NULL) {
905 import->filename = find_import_file(import->neededClass);
906 if (!import->filename) {
907 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
908 import->from, import->statement.lineno,
909 import->neededClass);
910 err |= 1;
911 } else {
912 err |= parse_aidl(import->filename);
913 import->doc = g_document;
914 if (import->doc == NULL) {
915 err |= 1;
916 }
917 }
918 }
919 import = import->next;
920 }
921 // bail out now if parsing wasn't successful
922 if (err != 0 || mainDoc == NULL) {
923 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
924 return 1;
925 }
926
927 // complain about ones that aren't in the right files
928 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
929 import = g_imports;
930 while (import) {
931 err |= check_filenames(import->filename, import->doc);
932 import = import->next;
933 }
934
935 // gather the types that have been declared
936 err |= gather_types(options.inputFileName.c_str(), mainDoc);
937 import = g_imports;
938 while (import) {
939 err |= gather_types(import->filename, import->doc);
940 import = import->next;
941 }
942
943#if 0
944 printf("---- main doc ----\n");
945 test_document(mainDoc);
946
947 import = g_imports;
948 while (import) {
949 printf("---- import doc ----\n");
950 test_document(import->doc);
951 import = import->next;
952 }
953 NAMES.Dump();
954#endif
955
956 // check the referenced types in mainDoc to make sure we've imported them
957 err |= check_types(options.inputFileName.c_str(), mainDoc);
958
959 // finally, there really only needs to be one thing in mainDoc, and it
960 // needs to be an interface.
961 bool onlyParcelable = false;
962 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
963
964 // If this includes an interface definition, then assign method ids and validate.
965 if (!onlyParcelable) {
966 err |= check_and_assign_method_ids(options.inputFileName.c_str(),
967 ((interface_type*)mainDoc)->interface_items);
968 }
969
970 // after this, there shouldn't be any more errors because of the
971 // input.
972 if (err != 0 || mainDoc == NULL) {
973 return 1;
974 }
975
976 // if needed, generate the outputFileName from the outputBaseFolder
977 if (options.outputFileName.length() == 0 &&
978 options.outputBaseFolder.length() > 0) {
979 options.outputFileName = generate_outputFileName(options, mainDoc);
980 }
981
982 // if we were asked to, generate a make dependency file
983 // unless it's a parcelable *and* it's supposed to fail on parcelable
984 if ((options.autoDepFile || options.depFileName != "") &&
985 !(onlyParcelable && options.failOnParcelable)) {
986 // make sure the folders of the output file all exists
987 check_outputFilePath(options.outputFileName);
988 generate_dep_file(options, mainDoc);
989 }
990
991 // they didn't ask to fail on parcelables, so just exit quietly.
992 if (onlyParcelable && !options.failOnParcelable) {
993 return 0;
994 }
995
996 // make sure the folders of the output file all exists
997 check_outputFilePath(options.outputFileName);
998
999 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1000 (interface_type*)mainDoc);
1001
1002 return err;
1003}
1004
Christopher Wiley2f774172015-08-30 10:57:07 -07001005int
Adam Lesinski282e1812014-01-23 18:17:42 -08001006preprocess_aidl(const Options& options)
1007{
1008 vector<string> lines;
1009 int err;
1010
1011 // read files
1012 int N = options.filesToPreprocess.size();
1013 for (int i=0; i<N; i++) {
1014 g_callbacks = &g_mainCallbacks;
1015 err = parse_aidl(options.filesToPreprocess[i].c_str());
1016 if (err != 0) {
1017 return err;
1018 }
1019 document_item_type* doc = g_document;
1020 string line;
1021 if (doc->item_type == USER_DATA_TYPE) {
1022 user_data_type* parcelable = (user_data_type*)doc;
Casey Dahlinca4543c2015-09-01 13:21:26 -07001023 if (parcelable->parcelable) {
Adam Lesinski282e1812014-01-23 18:17:42 -08001024 line = "parcelable ";
1025 }
Adam Lesinski282e1812014-01-23 18:17:42 -08001026 if (parcelable->package) {
1027 line += parcelable->package;
1028 line += '.';
1029 }
1030 line += parcelable->name.data;
1031 } else {
1032 line = "interface ";
1033 interface_type* iface = (interface_type*)doc;
1034 if (iface->package) {
1035 line += iface->package;
1036 line += '.';
1037 }
1038 line += iface->name.data;
1039 }
1040 line += ";\n";
1041 lines.push_back(line);
1042 }
1043
1044 // write preprocessed file
1045 int fd = open( options.outputFileName.c_str(),
1046 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
Elliott Hughese17788c2015-08-17 12:41:46 -07001047#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -08001048 _S_IREAD|_S_IWRITE);
1049#else
1050 S_IRUSR|S_IWUSR|S_IRGRP);
1051#endif
1052 if (fd == -1) {
1053 fprintf(stderr, "aidl: could not open file for write: %s\n",
1054 options.outputFileName.c_str());
1055 return 1;
1056 }
1057
1058 N = lines.size();
1059 for (int i=0; i<N; i++) {
1060 const string& s = lines[i];
1061 int len = s.length();
1062 if (len != write(fd, s.c_str(), len)) {
1063 fprintf(stderr, "aidl: error writing to file %s\n",
1064 options.outputFileName.c_str());
1065 close(fd);
1066 unlink(options.outputFileName.c_str());
1067 return 1;
1068 }
1069 }
1070
1071 close(fd);
1072 return 0;
1073}