blob: 14c9f95a247b1b2ceb4e2121dab822731fd08e51 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001
2#include "aidl_language.h"
3#include "options.h"
4#include "search_path.h"
5#include "Type.h"
6#include "generate_java.h"
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/param.h>
10#include <sys/stat.h>
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <map>
16
17#ifdef HAVE_MS_C_RUNTIME
18#include <io.h>
Andrew Hsiehc9d32392014-05-07 20:14:30 +080019#include <direct.h>
Adam Lesinski282e1812014-01-23 18:17:42 -080020#include <sys/stat.h>
21#endif
22
23#ifndef O_BINARY
24# define O_BINARY 0
25#endif
26
27// The following are gotten as the offset from the allowable id's between
28// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
29// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
30#define MIN_USER_SET_METHOD_ID 0
31#define MAX_USER_SET_METHOD_ID 16777214
32
33using namespace std;
34
35static void
36test_document(document_item_type* d)
37{
38 while (d) {
39 if (d->item_type == INTERFACE_TYPE_BINDER) {
40 interface_type* c = (interface_type*)d;
41 printf("interface %s %s {\n", c->package, c->name.data);
42 interface_item_type *q = (interface_item_type*)c->interface_items;
43 while (q) {
44 if (q->item_type == METHOD_TYPE) {
45 method_type *m = (method_type*)q;
46 printf(" %s %s(", m->type.type.data, m->name.data);
47 arg_type *p = m->args;
48 while (p) {
49 printf("%s %s",p->type.type.data,p->name.data);
50 if (p->next) printf(", ");
51 p=p->next;
52 }
53 printf(")");
54 printf(";\n");
55 }
56 q=q->next;
57 }
58 printf("}\n");
59 }
60 else if (d->item_type == USER_DATA_TYPE) {
61 user_data_type* b = (user_data_type*)d;
62 if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
63 printf("parcelable %s %s;\n", b->package, b->name.data);
64 }
65 if ((b->flattening_methods & RPC_DATA) != 0) {
66 printf("flattenable %s %s;\n", b->package, b->name.data);
67 }
68 }
69 else {
70 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
71 }
72 d = d->next;
73 }
74}
75
76// ==========================================================
77int
78convert_direction(const char* direction)
79{
80 if (direction == NULL) {
81 return IN_PARAMETER;
82 }
83 if (0 == strcmp(direction, "in")) {
84 return IN_PARAMETER;
85 }
86 if (0 == strcmp(direction, "out")) {
87 return OUT_PARAMETER;
88 }
89 return INOUT_PARAMETER;
90}
91
92// ==========================================================
93struct import_info {
94 const char* from;
95 const char* filename;
96 buffer_type statement;
97 const char* neededClass;
98 document_item_type* doc;
99 struct import_info* next;
100};
101
102document_item_type* g_document = NULL;
103import_info* g_imports = NULL;
104
105static void
106main_document_parsed(document_item_type* d)
107{
108 g_document = d;
109}
110
111static void
112main_import_parsed(buffer_type* statement)
113{
114 import_info* import = (import_info*)malloc(sizeof(import_info));
115 memset(import, 0, sizeof(import_info));
116 import->from = strdup(g_currentFilename);
117 import->statement.lineno = statement->lineno;
118 import->statement.data = strdup(statement->data);
119 import->statement.extra = NULL;
120 import->next = g_imports;
121 import->neededClass = parse_import_statement(statement->data);
122 g_imports = import;
123}
124
125static ParserCallbacks g_mainCallbacks = {
126 &main_document_parsed,
127 &main_import_parsed
128};
129
130char*
131parse_import_statement(const char* text)
132{
133 const char* end;
134 int len;
135
136 while (isspace(*text)) {
137 text++;
138 }
139 while (!isspace(*text)) {
140 text++;
141 }
142 while (isspace(*text)) {
143 text++;
144 }
145 end = text;
146 while (!isspace(*end) && *end != ';') {
147 end++;
148 }
149 len = end-text;
150
151 char* rv = (char*)malloc(len+1);
152 memcpy(rv, text, len);
153 rv[len] = '\0';
154
155 return rv;
156}
157
158// ==========================================================
159static void
160import_import_parsed(buffer_type* statement)
161{
162}
163
164static ParserCallbacks g_importCallbacks = {
165 &main_document_parsed,
166 &import_import_parsed
167};
168
169// ==========================================================
170static int
171check_filename(const char* filename, const char* package, buffer_type* name)
172{
173 const char* p;
174 string expected;
175 string fn;
176 size_t len;
177 char cwd[MAXPATHLEN];
178 bool valid = false;
179
180#ifdef HAVE_WINDOWS_PATHS
181 if (isalpha(filename[0]) && filename[1] == ':'
182 && filename[2] == OS_PATH_SEPARATOR) {
183#else
184 if (filename[0] == OS_PATH_SEPARATOR) {
185#endif
186 fn = filename;
187 } else {
188 fn = getcwd(cwd, sizeof(cwd));
189 len = fn.length();
190 if (fn[len-1] != OS_PATH_SEPARATOR) {
191 fn += OS_PATH_SEPARATOR;
192 }
193 fn += filename;
194 }
195
196 if (package) {
197 expected = package;
198 expected += '.';
199 }
200
201 len = expected.length();
202 for (size_t i=0; i<len; i++) {
203 if (expected[i] == '.') {
204 expected[i] = OS_PATH_SEPARATOR;
205 }
206 }
207
208 p = strchr(name->data, '.');
209 len = p ? p-name->data : strlen(name->data);
210 expected.append(name->data, len);
211
212 expected += ".aidl";
213
214 len = fn.length();
215 valid = (len >= expected.length());
216
217 if (valid) {
218 p = fn.c_str() + (len - expected.length());
219
220#ifdef HAVE_WINDOWS_PATHS
221 if (OS_PATH_SEPARATOR != '/') {
222 // Input filename under cygwin most likely has / separators
223 // whereas the expected string uses \\ separators. Adjust
224 // them accordingly.
225 for (char *c = const_cast<char *>(p); *c; ++c) {
226 if (*c == '/') *c = OS_PATH_SEPARATOR;
227 }
228 }
229#endif
230
Yabin Cuifb8e2b12014-11-10 15:01:43 -0800231 // aidl assumes case-insensitivity on Mac Os and Windows.
232#if defined(__linux__)
Adam Lesinski282e1812014-01-23 18:17:42 -0800233 valid = (expected == p);
234#else
235 valid = !strcasecmp(expected.c_str(), p);
236#endif
237 }
238
239 if (!valid) {
240 fprintf(stderr, "%s:%d interface %s should be declared in a file"
241 " called %s.\n",
242 filename, name->lineno, name->data, expected.c_str());
243 return 1;
244 }
245
246 return 0;
247}
248
249static int
250check_filenames(const char* filename, document_item_type* items)
251{
252 int err = 0;
253 while (items) {
254 if (items->item_type == USER_DATA_TYPE) {
255 user_data_type* p = (user_data_type*)items;
256 err |= check_filename(filename, p->package, &p->name);
257 }
258 else if (items->item_type == INTERFACE_TYPE_BINDER
259 || items->item_type == INTERFACE_TYPE_RPC) {
260 interface_type* c = (interface_type*)items;
261 err |= check_filename(filename, c->package, &c->name);
262 }
263 else {
264 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
265 items->item_type);
266 return 1;
267 }
268 items = items->next;
269 }
270 return err;
271}
272
273// ==========================================================
274static const char*
275kind_to_string(int kind)
276{
277 switch (kind)
278 {
279 case Type::INTERFACE:
280 return "an interface";
281 case Type::USERDATA:
282 return "a user data";
283 default:
284 return "ERROR";
285 }
286}
287
288static char*
289rfind(char* str, char c)
290{
291 char* p = str + strlen(str) - 1;
292 while (p >= str) {
293 if (*p == c) {
294 return p;
295 }
296 p--;
297 }
298 return NULL;
299}
300
301static int
302gather_types(const char* filename, document_item_type* items)
303{
304 int err = 0;
305 while (items) {
306 Type* type;
307 if (items->item_type == USER_DATA_TYPE) {
308 user_data_type* p = (user_data_type*)items;
309 type = new UserDataType(p->package ? p->package : "", p->name.data,
310 false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
311 ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
312 }
313 else if (items->item_type == INTERFACE_TYPE_BINDER
314 || items->item_type == INTERFACE_TYPE_RPC) {
315 interface_type* c = (interface_type*)items;
316 type = new InterfaceType(c->package ? c->package : "",
317 c->name.data, false, c->oneway,
318 filename, c->name.lineno);
319 }
320 else {
321 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
322 return 1;
323 }
324
325 Type* old = NAMES.Find(type->QualifiedName());
326 if (old == NULL) {
327 NAMES.Add(type);
328
329 if (items->item_type == INTERFACE_TYPE_BINDER) {
330 // for interfaces, also add the stub and proxy types, we don't
331 // bother checking these for duplicates, because the parser
332 // won't let us do it.
333 interface_type* c = (interface_type*)items;
334
335 string name = c->name.data;
336 name += ".Stub";
337 Type* stub = new Type(c->package ? c->package : "",
338 name, Type::GENERATED, false, false, false,
339 filename, c->name.lineno);
340 NAMES.Add(stub);
341
342 name = c->name.data;
343 name += ".Stub.Proxy";
344 Type* proxy = new Type(c->package ? c->package : "",
345 name, Type::GENERATED, false, false, false,
346 filename, c->name.lineno);
347 NAMES.Add(proxy);
348 }
349 else if (items->item_type == INTERFACE_TYPE_RPC) {
350 // for interfaces, also add the service base type, we don't
351 // bother checking these for duplicates, because the parser
352 // won't let us do it.
353 interface_type* c = (interface_type*)items;
354
355 string name = c->name.data;
356 name += ".ServiceBase";
357 Type* base = new Type(c->package ? c->package : "",
358 name, Type::GENERATED, false, false, false,
359 filename, c->name.lineno);
360 NAMES.Add(base);
361 }
362 } else {
363 if (old->Kind() == Type::BUILT_IN) {
364 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
365 filename, type->DeclLine(),
366 type->QualifiedName().c_str());
367 err = 1;
368 }
369 else if (type->Kind() != old->Kind()) {
370 const char* oldKind = kind_to_string(old->Kind());
371 const char* newKind = kind_to_string(type->Kind());
372
373 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
374 filename, type->DeclLine(),
375 type->QualifiedName().c_str(), newKind);
376 fprintf(stderr, "%s:%d previously defined here as %s.\n",
377 old->DeclFile().c_str(), old->DeclLine(), oldKind);
378 err = 1;
379 }
380 }
381
382 items = items->next;
383 }
384 return err;
385}
386
387// ==========================================================
388static bool
389matches_keyword(const char* str)
390{
391 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
392 "byte", "case", "catch", "char", "class", "const", "continue",
393 "default", "do", "double", "else", "enum", "extends", "final",
394 "finally", "float", "for", "goto", "if", "implements", "import",
395 "instanceof", "int", "interface", "long", "native", "new", "package",
396 "private", "protected", "public", "return", "short", "static",
397 "strictfp", "super", "switch", "synchronized", "this", "throw",
398 "throws", "transient", "try", "void", "volatile", "while",
399 "true", "false", "null",
400 NULL
401 };
402 const char** k = KEYWORDS;
403 while (*k) {
404 if (0 == strcmp(str, *k)) {
405 return true;
406 }
407 k++;
408 }
409 return false;
410}
411
412static int
413check_method(const char* filename, int kind, method_type* m)
414{
415 int err = 0;
416
417 // return type
418 Type* returnType = NAMES.Search(m->type.type.data);
419 if (returnType == NULL) {
420 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
421 m->type.type.lineno, m->type.type.data);
422 err = 1;
423 return err;
424 }
425
426 if (returnType == EVENT_FAKE_TYPE) {
427 if (kind != INTERFACE_TYPE_RPC) {
428 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
429 filename, m->type.type.lineno);
430 err = 1;
431 }
432 } else {
433 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
434 : returnType->CanWriteToRpcData())) {
435 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
436 m->type.type.lineno, m->type.type.data);
437 err = 1;
438 }
439 }
440
441 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
442 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
443 m->type.array_token.lineno, m->type.type.data,
444 m->type.array_token.data);
445 err = 1;
446 }
447
448 if (m->type.dimension > 1) {
449 fprintf(stderr, "%s:%d return type %s%s only one"
450 " dimensional arrays are supported\n", filename,
451 m->type.array_token.lineno, m->type.type.data,
452 m->type.array_token.data);
453 err = 1;
454 }
455
456 int index = 1;
457
458 arg_type* arg = m->args;
459 while (arg) {
460 Type* t = NAMES.Search(arg->type.type.data);
461
462 // check the arg type
463 if (t == NULL) {
464 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
465 filename, m->type.type.lineno, arg->name.data, index,
466 arg->type.type.data);
467 err = 1;
468 goto next;
469 }
470
471 if (t == EVENT_FAKE_TYPE) {
472 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
473 filename, m->type.type.lineno, arg->name.data, index,
474 arg->type.type.data);
475 err = 1;
476 goto next;
477 }
478
479 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
480 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
481 filename, m->type.type.lineno, index,
482 arg->type.type.data, arg->name.data);
483 err = 1;
484 }
485
486 if (returnType == EVENT_FAKE_TYPE
487 && convert_direction(arg->direction.data) != IN_PARAMETER) {
488 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
489 filename, m->type.type.lineno, index,
490 arg->type.type.data, arg->name.data);
491 err = 1;
492 goto next;
493 }
494
495 if (arg->direction.data == NULL
496 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
497 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
498 " parameter, so you must declare it as in,"
499 " out or inout.\n",
500 filename, m->type.type.lineno, index,
501 arg->type.type.data, arg->name.data);
502 err = 1;
503 }
504
505 if (convert_direction(arg->direction.data) != IN_PARAMETER
506 && !t->CanBeOutParameter()
507 && arg->type.dimension == 0) {
508 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
509 " parameter.\n",
510 filename, m->type.type.lineno, index,
511 arg->direction.data, arg->type.type.data,
512 arg->name.data);
513 err = 1;
514 }
515
516 if (arg->type.dimension > 0 && !t->CanBeArray()) {
517 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
518 " array.\n", filename,
519 m->type.array_token.lineno, index, arg->direction.data,
520 arg->type.type.data, arg->type.array_token.data,
521 arg->name.data);
522 err = 1;
523 }
524
525 if (arg->type.dimension > 1) {
526 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
527 " dimensional arrays are supported\n", filename,
528 m->type.array_token.lineno, index, arg->direction.data,
529 arg->type.type.data, arg->type.array_token.data,
530 arg->name.data);
531 err = 1;
532 }
533
534 // check that the name doesn't match a keyword
535 if (matches_keyword(arg->name.data)) {
536 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
537 " Java or aidl keyword\n",
538 filename, m->name.lineno, index, arg->name.data);
539 err = 1;
540 }
541
542next:
543 index++;
544 arg = arg->next;
545 }
546
547 return err;
548}
549
550static int
551check_types(const char* filename, document_item_type* items)
552{
553 int err = 0;
554 while (items) {
555 // (nothing to check for USER_DATA_TYPE)
556 if (items->item_type == INTERFACE_TYPE_BINDER
557 || items->item_type == INTERFACE_TYPE_RPC) {
558 map<string,method_type*> methodNames;
559 interface_type* c = (interface_type*)items;
560
561 interface_item_type* member = c->interface_items;
562 while (member) {
563 if (member->item_type == METHOD_TYPE) {
564 method_type* m = (method_type*)member;
565
566 err |= check_method(filename, items->item_type, m);
567
568 // prevent duplicate methods
569 if (methodNames.find(m->name.data) == methodNames.end()) {
570 methodNames[m->name.data] = m;
571 } else {
572 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
573 filename, m->name.lineno, m->name.data);
574 method_type* old = methodNames[m->name.data];
575 fprintf(stderr, "%s:%d previously defined here.\n",
576 filename, old->name.lineno);
577 err = 1;
578 }
579 }
580 member = member->next;
581 }
582 }
583
584 items = items->next;
585 }
586 return err;
587}
588
589// ==========================================================
590static int
591exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
592 bool* onlyParcelable)
593{
594 if (items == NULL) {
595 fprintf(stderr, "%s: file does not contain any interfaces\n",
596 filename);
597 return 1;
598 }
599
600 const document_item_type* next = items->next;
601 // Allow parcelables to skip the "one-only" rule.
602 if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
603 int lineno = -1;
604 if (next->item_type == INTERFACE_TYPE_BINDER) {
605 lineno = ((interface_type*)next)->interface_token.lineno;
606 }
607 else if (next->item_type == INTERFACE_TYPE_RPC) {
608 lineno = ((interface_type*)next)->interface_token.lineno;
609 }
610 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
611 filename, lineno);
612 return 1;
613 }
614
615 if (items->item_type == USER_DATA_TYPE) {
616 *onlyParcelable = true;
617 if (options.failOnParcelable) {
618 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
619 " parcelables or flattenables,\n", filename,
620 ((user_data_type*)items)->keyword_token.lineno);
621 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
622 "may not go in the Makefile.\n", filename,
623 ((user_data_type*)items)->keyword_token.lineno);
624 return 1;
625 }
626 } else {
627 *onlyParcelable = false;
628 }
629
630 return 0;
631}
632
633// ==========================================================
634void
635generate_dep_file(const Options& options, const document_item_type* items)
636{
637 /* we open the file in binary mode to ensure that the same output is
638 * generated on all platforms !!
639 */
640 FILE* to = NULL;
641 if (options.autoDepFile) {
642 string fileName = options.outputFileName + ".d";
643 to = fopen(fileName.c_str(), "wb");
644 } else {
645 to = fopen(options.depFileName.c_str(), "wb");
646 }
647
648 if (to == NULL) {
649 return;
650 }
651
652 const char* slash = "\\";
653 import_info* import = g_imports;
654 if (import == NULL) {
655 slash = "";
656 }
657
658 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
659 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
660 } else {
661 // parcelable: there's no output file.
662 fprintf(to, " : \\\n");
663 }
664 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
665
666 while (import) {
667 if (import->next == NULL) {
668 slash = "";
669 }
670 if (import->filename) {
671 fprintf(to, " %s %s\n", import->filename, slash);
672 }
673 import = import->next;
674 }
675
676 fprintf(to, "\n");
677
678 // 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) {
752#ifdef HAVE_MS_C_RUNTIME
753 _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// ==========================================================
936static int
937compile_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
1066static int
1067preprocess_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,
1111#ifdef HAVE_MS_C_RUNTIME
1112 _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}
1138
1139// ==========================================================
1140int
1141main(int argc, const char **argv)
1142{
1143 Options options;
1144 int result = parse_options(argc, argv, &options);
1145 if (result) {
1146 return result;
1147 }
1148
1149 switch (options.task)
1150 {
1151 case COMPILE_AIDL:
1152 return compile_aidl(options);
1153 case PREPROCESS_AIDL:
1154 return preprocess_aidl(options);
1155 }
1156 fprintf(stderr, "aidl: internal error\n");
1157 return 1;
1158}