blob: e311af55a8c51012c210a528da5ee9b1bc719d93 [file] [log] [blame]
Christopher Wiley89eaab52015-09-15 14:46:46 -07001/*
2 * Copyright (C) 2015, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Adam Lesinskiffa16862014-01-23 18:17:42 -080016
Christopher Wileyf690be52015-09-14 15:19:10 -070017#include "aidl.h"
Adam Lesinskiffa16862014-01-23 18:17:42 -080018
Christopher Wileyf690be52015-09-14 15:19:10 -070019#include <fcntl.h>
Christopher Wileyc16e5e72015-09-16 10:49:40 -070020#include <iostream>
Christopher Wileyf690be52015-09-14 15:19:10 -070021#include <map>
Adam Lesinskiffa16862014-01-23 18:17:42 -080022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Christopher Wileyf690be52015-09-14 15:19:10 -070025#include <sys/param.h>
26#include <sys/stat.h>
27#include <unistd.h>
Adam Lesinskiffa16862014-01-23 18:17:42 -080028
Elliott Hughes549b6e22015-08-17 12:41:46 -070029#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -080030#include <io.h>
Andrew Hsieh15ce9942014-05-07 20:14:30 +080031#include <direct.h>
Adam Lesinskiffa16862014-01-23 18:17:42 -080032#include <sys/stat.h>
33#endif
34
Christopher Wileyf690be52015-09-14 15:19:10 -070035
Christopher Wileyf690be52015-09-14 15:19:10 -070036#include "aidl_language.h"
Christopher Wileyeb1acc12015-09-16 11:25:13 -070037#include "generate_cpp.h"
Christopher Wileyf690be52015-09-14 15:19:10 -070038#include "generate_java.h"
39#include "logging.h"
40#include "options.h"
41#include "os.h"
42#include "parse_helpers.h"
43#include "search_path.h"
Christopher Wiley775fa1f2015-09-22 15:00:12 -070044#include "type_java.h"
Christopher Wiley84c1eac2015-09-23 13:29:28 -070045#include "type_namespace.h"
Christopher Wileyf690be52015-09-14 15:19:10 -070046
Adam Lesinskiffa16862014-01-23 18:17:42 -080047#ifndef O_BINARY
48# define O_BINARY 0
49#endif
50
Christopher Wileyc16e5e72015-09-16 10:49:40 -070051using std::cerr;
52using std::endl;
Christopher Wiley9f4c7ae2015-08-24 14:07:32 -070053using std::map;
54using std::set;
55using std::string;
Christopher Wiley84c1eac2015-09-23 13:29:28 -070056using std::unique_ptr;
Christopher Wiley9f4c7ae2015-08-24 14:07:32 -070057using std::vector;
Adam Lesinskiffa16862014-01-23 18:17:42 -080058
Christopher Wileyf690be52015-09-14 15:19:10 -070059namespace android {
60namespace aidl {
61namespace {
Adam Lesinskiffa16862014-01-23 18:17:42 -080062
Christopher Wileyf690be52015-09-14 15:19:10 -070063// The following are gotten as the offset from the allowable id's between
64// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
65// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
66const int kMinUserSetMethodId = 0;
67const int kMaxUserSetMethodId = 16777214;
Adam Lesinskiffa16862014-01-23 18:17:42 -080068
Christopher Wileyf690be52015-09-14 15:19:10 -070069int check_filename(const char* filename,
70 const char* package,
71 buffer_type* name) {
Adam Lesinskiffa16862014-01-23 18:17:42 -080072 const char* p;
73 string expected;
74 string fn;
75 size_t len;
76 char cwd[MAXPATHLEN];
77 bool valid = false;
78
Elliott Hughesce310da2015-07-29 08:44:17 -070079#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -080080 if (isalpha(filename[0]) && filename[1] == ':'
81 && filename[2] == OS_PATH_SEPARATOR) {
82#else
83 if (filename[0] == OS_PATH_SEPARATOR) {
84#endif
85 fn = filename;
86 } else {
87 fn = getcwd(cwd, sizeof(cwd));
88 len = fn.length();
89 if (fn[len-1] != OS_PATH_SEPARATOR) {
90 fn += OS_PATH_SEPARATOR;
91 }
92 fn += filename;
93 }
94
95 if (package) {
96 expected = package;
97 expected += '.';
98 }
99
100 len = expected.length();
101 for (size_t i=0; i<len; i++) {
102 if (expected[i] == '.') {
103 expected[i] = OS_PATH_SEPARATOR;
104 }
105 }
106
107 p = strchr(name->data, '.');
108 len = p ? p-name->data : strlen(name->data);
109 expected.append(name->data, len);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700110
Adam Lesinskiffa16862014-01-23 18:17:42 -0800111 expected += ".aidl";
112
113 len = fn.length();
114 valid = (len >= expected.length());
115
116 if (valid) {
117 p = fn.c_str() + (len - expected.length());
118
Elliott Hughesce310da2015-07-29 08:44:17 -0700119#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800120 if (OS_PATH_SEPARATOR != '/') {
121 // Input filename under cygwin most likely has / separators
122 // whereas the expected string uses \\ separators. Adjust
123 // them accordingly.
124 for (char *c = const_cast<char *>(p); *c; ++c) {
125 if (*c == '/') *c = OS_PATH_SEPARATOR;
126 }
127 }
128#endif
129
Yabin Cui482eefb2014-11-10 15:01:43 -0800130 // aidl assumes case-insensitivity on Mac Os and Windows.
131#if defined(__linux__)
Adam Lesinskiffa16862014-01-23 18:17:42 -0800132 valid = (expected == p);
133#else
134 valid = !strcasecmp(expected.c_str(), p);
135#endif
136 }
137
138 if (!valid) {
139 fprintf(stderr, "%s:%d interface %s should be declared in a file"
140 " called %s.\n",
141 filename, name->lineno, name->data, expected.c_str());
142 return 1;
143 }
144
145 return 0;
146}
147
Christopher Wileyf690be52015-09-14 15:19:10 -0700148int check_filenames(const char* filename, document_item_type* items) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800149 int err = 0;
150 while (items) {
151 if (items->item_type == USER_DATA_TYPE) {
152 user_data_type* p = (user_data_type*)items;
153 err |= check_filename(filename, p->package, &p->name);
154 }
Casey Dahlin88868fc2015-09-01 13:21:26 -0700155 else if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800156 interface_type* c = (interface_type*)items;
157 err |= check_filename(filename, c->package, &c->name);
158 }
159 else {
160 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
161 items->item_type);
162 return 1;
163 }
164 items = items->next;
165 }
166 return err;
167}
168
Christopher Wileyf690be52015-09-14 15:19:10 -0700169char* rfind(char* str, char c) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800170 char* p = str + strlen(str) - 1;
171 while (p >= str) {
172 if (*p == c) {
173 return p;
174 }
175 p--;
176 }
177 return NULL;
178}
179
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700180bool gather_types(const char* raw_filename,
181 document_item_type* all_items,
182 TypeNamespace* types) {
183 bool success = true;
184 if (raw_filename == nullptr)
185 raw_filename = "";
186 const std::string filename{raw_filename};
Adam Lesinskiffa16862014-01-23 18:17:42 -0800187
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700188 for (document_item_type* item = all_items; item; item = item->next) {
189 if (item->item_type == USER_DATA_TYPE) {
190 user_data_type* p = (user_data_type*)item;
191 success &= types->AddParcelableType(p, filename);
192 } else if (item->item_type == INTERFACE_TYPE_BINDER) {
193 interface_type* c = (interface_type*)item;
194 success &= types->AddBinderType(c, filename);
195 } else {
196 LOG(FATAL) << "internal error";
Adam Lesinskiffa16862014-01-23 18:17:42 -0800197 }
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700198 }
199 return success;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800200}
201
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700202int check_method(const char* filename, method_type* m, TypeNamespace* types) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800203 int err = 0;
204
205 // return type
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700206 const Type* returnType = types->Search(m->type.type.data);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800207 if (returnType == NULL) {
208 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
209 m->type.type.lineno, m->type.type.data);
210 err = 1;
211 return err;
212 }
213
Casey Dahlin88868fc2015-09-01 13:21:26 -0700214 if (!returnType->CanWriteToParcel()) {
215 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
Adam Lesinskiffa16862014-01-23 18:17:42 -0800216 m->type.type.lineno, m->type.type.data);
Casey Dahlin88868fc2015-09-01 13:21:26 -0700217 err = 1;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800218 }
219
220 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
221 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
222 m->type.array_token.lineno, m->type.type.data,
223 m->type.array_token.data);
224 err = 1;
225 }
226
227 if (m->type.dimension > 1) {
228 fprintf(stderr, "%s:%d return type %s%s only one"
229 " dimensional arrays are supported\n", filename,
230 m->type.array_token.lineno, m->type.type.data,
231 m->type.array_token.data);
232 err = 1;
233 }
234
235 int index = 1;
236
237 arg_type* arg = m->args;
238 while (arg) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700239 const Type* t = types->Search(arg->type.type.data);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800240
241 // check the arg type
242 if (t == NULL) {
243 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
244 filename, m->type.type.lineno, arg->name.data, index,
245 arg->type.type.data);
246 err = 1;
247 goto next;
248 }
249
Casey Dahlin88868fc2015-09-01 13:21:26 -0700250 if (!t->CanWriteToParcel()) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800251 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
252 filename, m->type.type.lineno, index,
253 arg->type.type.data, arg->name.data);
254 err = 1;
255 }
256
Adam Lesinskiffa16862014-01-23 18:17:42 -0800257 if (arg->direction.data == NULL
258 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
259 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
260 " parameter, so you must declare it as in,"
261 " out or inout.\n",
262 filename, m->type.type.lineno, index,
263 arg->type.type.data, arg->name.data);
264 err = 1;
265 }
266
267 if (convert_direction(arg->direction.data) != IN_PARAMETER
268 && !t->CanBeOutParameter()
269 && arg->type.dimension == 0) {
270 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
271 " parameter.\n",
272 filename, m->type.type.lineno, index,
273 arg->direction.data, arg->type.type.data,
274 arg->name.data);
275 err = 1;
276 }
277
278 if (arg->type.dimension > 0 && !t->CanBeArray()) {
279 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
280 " array.\n", filename,
281 m->type.array_token.lineno, index, arg->direction.data,
282 arg->type.type.data, arg->type.array_token.data,
283 arg->name.data);
284 err = 1;
285 }
286
287 if (arg->type.dimension > 1) {
288 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
289 " dimensional arrays are supported\n", filename,
290 m->type.array_token.lineno, index, arg->direction.data,
291 arg->type.type.data, arg->type.array_token.data,
292 arg->name.data);
293 err = 1;
294 }
295
296 // check that the name doesn't match a keyword
Christopher Wileyf690be52015-09-14 15:19:10 -0700297 if (is_java_keyword(arg->name.data)) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800298 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
299 " Java or aidl keyword\n",
300 filename, m->name.lineno, index, arg->name.data);
301 err = 1;
302 }
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700303
Casey Dahlin281d6f02015-09-23 16:29:44 -0700304 // Reserve a namespace for internal use
305 if (!strncmp(arg->name.data, "_aidl", 5)) {
306 fprintf(stderr, "%s:%d parameter %d %s cannot begin with"
307 " '_aidl'\n",
308 filename, m->name.lineno, index, arg->name.data);
309 err = 1;
310 }
311
Adam Lesinskiffa16862014-01-23 18:17:42 -0800312next:
313 index++;
314 arg = arg->next;
315 }
316
317 return err;
318}
319
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700320int check_types(const char* filename,
321 document_item_type* items,
322 TypeNamespace* types) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800323 int err = 0;
324 while (items) {
325 // (nothing to check for USER_DATA_TYPE)
Casey Dahlin88868fc2015-09-01 13:21:26 -0700326 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800327 map<string,method_type*> methodNames;
328 interface_type* c = (interface_type*)items;
329
330 interface_item_type* member = c->interface_items;
331 while (member) {
332 if (member->item_type == METHOD_TYPE) {
333 method_type* m = (method_type*)member;
334
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700335 err |= check_method(filename, m, types);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800336
337 // prevent duplicate methods
338 if (methodNames.find(m->name.data) == methodNames.end()) {
339 methodNames[m->name.data] = m;
340 } else {
341 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
342 filename, m->name.lineno, m->name.data);
343 method_type* old = methodNames[m->name.data];
344 fprintf(stderr, "%s:%d previously defined here.\n",
345 filename, old->name.lineno);
346 err = 1;
347 }
348 }
349 member = member->next;
350 }
351 }
352
353 items = items->next;
354 }
355 return err;
356}
357
Christopher Wileyf690be52015-09-14 15:19:10 -0700358void generate_dep_file(const JavaOptions& options,
359 const document_item_type* items,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700360 import_info* import_head) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800361 /* we open the file in binary mode to ensure that the same output is
362 * generated on all platforms !!
363 */
364 FILE* to = NULL;
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700365 if (options.auto_dep_file_) {
366 string fileName = options.output_file_name_ + ".d";
Adam Lesinskiffa16862014-01-23 18:17:42 -0800367 to = fopen(fileName.c_str(), "wb");
368 } else {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700369 to = fopen(options.dep_file_name_.c_str(), "wb");
Adam Lesinskiffa16862014-01-23 18:17:42 -0800370 }
371
372 if (to == NULL) {
373 return;
374 }
375
376 const char* slash = "\\";
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700377 import_info* import = import_head;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800378 if (import == NULL) {
379 slash = "";
380 }
381
Casey Dahlin88868fc2015-09-01 13:21:26 -0700382 if (items->item_type == INTERFACE_TYPE_BINDER) {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700383 fprintf(to, "%s: \\\n", options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800384 } else {
385 // parcelable: there's no output file.
386 fprintf(to, " : \\\n");
387 }
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700388 fprintf(to, " %s %s\n", options.input_file_name_.c_str(), slash);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800389
390 while (import) {
391 if (import->next == NULL) {
392 slash = "";
393 }
394 if (import->filename) {
395 fprintf(to, " %s %s\n", import->filename, slash);
396 }
397 import = import->next;
398 }
399
400 fprintf(to, "\n");
401
Ying Wang0e4861a2015-07-22 17:42:35 -0700402 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
403 // has been deleted, moved or renamed in incremental build.
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700404 fprintf(to, "%s :\n", options.input_file_name_.c_str());
Ying Wang0e4861a2015-07-22 17:42:35 -0700405
Adam Lesinskiffa16862014-01-23 18:17:42 -0800406 // Output "<imported_file>: " so make won't fail if the imported file has
407 // been deleted, moved or renamed in incremental build.
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700408 import = import_head;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800409 while (import) {
410 if (import->filename) {
411 fprintf(to, "%s :\n", import->filename);
412 }
413 import = import->next;
414 }
415
416 fclose(to);
417}
418
Christopher Wileyf690be52015-09-14 15:19:10 -0700419string generate_outputFileName2(const JavaOptions& options,
420 const buffer_type& name,
421 const char* package) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800422 string result;
423
424 // create the path to the destination folder based on the
425 // interface package name
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700426 result = options.output_base_folder_;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800427 result += OS_PATH_SEPARATOR;
428
429 string packageStr = package;
430 size_t len = packageStr.length();
431 for (size_t i=0; i<len; i++) {
432 if (packageStr[i] == '.') {
433 packageStr[i] = OS_PATH_SEPARATOR;
434 }
435 }
436
437 result += packageStr;
438
439 // add the filename by replacing the .aidl extension to .java
440 const char* p = strchr(name.data, '.');
441 len = p ? p-name.data : strlen(name.data);
442
443 result += OS_PATH_SEPARATOR;
444 result.append(name.data, len);
445 result += ".java";
446
447 return result;
448}
449
Christopher Wileyf690be52015-09-14 15:19:10 -0700450string generate_outputFileName(const JavaOptions& options,
451 const document_item_type* items) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800452 // items has already been checked to have only one interface.
Casey Dahlin88868fc2015-09-01 13:21:26 -0700453 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800454 interface_type* type = (interface_type*)items;
455
456 return generate_outputFileName2(options, type->name, type->package);
457 } else if (items->item_type == USER_DATA_TYPE) {
458 user_data_type* type = (user_data_type*)items;
459 return generate_outputFileName2(options, type->name, type->package);
460 }
461
462 // I don't think we can come here, but safer than returning NULL.
463 string result;
464 return result;
465}
466
467
Christopher Wileyf690be52015-09-14 15:19:10 -0700468void check_outputFilePath(const string& path) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800469 size_t len = path.length();
470 for (size_t i=0; i<len ; i++) {
471 if (path[i] == OS_PATH_SEPARATOR) {
472 string p = path.substr(0, i);
473 if (access(path.data(), F_OK) != 0) {
Elliott Hughes549b6e22015-08-17 12:41:46 -0700474#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800475 _mkdir(p.data());
476#else
477 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
478#endif
479 }
480 }
481 }
482}
483
484
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700485int parse_preprocessed_file(const string& filename, TypeNamespace* types) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800486 FILE* f = fopen(filename.c_str(), "rb");
487 if (f == NULL) {
488 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
489 filename.c_str());
490 return 1;
491 }
492
493 int lineno = 1;
494 char line[1024];
495 char type[1024];
496 char fullname[1024];
497 while (fgets(line, sizeof(line), f)) {
498 // skip comments and empty lines
499 if (!line[0] || strncmp(line, "//", 2) == 0) {
500 continue;
501 }
502
503 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
504
505 char* packagename;
506 char* classname = rfind(fullname, '.');
507 if (classname != NULL) {
508 *classname = '\0';
509 classname++;
510 packagename = fullname;
511 } else {
512 classname = fullname;
513 packagename = NULL;
514 }
515
516 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
517 // type, packagename, classname);
518 document_item_type* doc;
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700519
Adam Lesinskiffa16862014-01-23 18:17:42 -0800520 if (0 == strcmp("parcelable", type)) {
521 user_data_type* parcl = (user_data_type*)malloc(
522 sizeof(user_data_type));
523 memset(parcl, 0, sizeof(user_data_type));
524 parcl->document_item.item_type = USER_DATA_TYPE;
525 parcl->keyword_token.lineno = lineno;
526 parcl->keyword_token.data = strdup(type);
527 parcl->package = packagename ? strdup(packagename) : NULL;
528 parcl->name.lineno = lineno;
529 parcl->name.data = strdup(classname);
530 parcl->semicolon_token.lineno = lineno;
531 parcl->semicolon_token.data = strdup(";");
Casey Dahlin88868fc2015-09-01 13:21:26 -0700532 parcl->parcelable = true;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800533 doc = (document_item_type*)parcl;
534 }
535 else if (0 == strcmp("interface", type)) {
536 interface_type* iface = (interface_type*)malloc(
537 sizeof(interface_type));
538 memset(iface, 0, sizeof(interface_type));
539 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
540 iface->interface_token.lineno = lineno;
541 iface->interface_token.data = strdup(type);
542 iface->package = packagename ? strdup(packagename) : NULL;
543 iface->name.lineno = lineno;
544 iface->name.data = strdup(classname);
545 iface->open_brace_token.lineno = lineno;
546 iface->open_brace_token.data = strdup("{");
547 iface->close_brace_token.lineno = lineno;
548 iface->close_brace_token.data = strdup("}");
549 doc = (document_item_type*)iface;
550 }
551 else {
552 fprintf(stderr, "%s:%d: bad type in line: %s\n",
553 filename.c_str(), lineno, line);
Elliott Hughes5cd06072013-10-29 15:25:52 -0700554 fclose(f);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800555 return 1;
556 }
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700557 if (!gather_types(filename.c_str(), doc, types)) {
558 fprintf(stderr, "Failed to gather types for preprocessed aidl.\n");
559 fclose(f);
560 return 1;
561 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800562 lineno++;
563 }
564
565 if (!feof(f)) {
566 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
567 filename.c_str(), lineno);
568 return 1;
569 }
570
571 fclose(f);
572 return 0;
573}
574
Christopher Wileyf690be52015-09-14 15:19:10 -0700575int check_and_assign_method_ids(const char * filename,
576 interface_item_type* first_item) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800577 // Check whether there are any methods with manually assigned id's and any that are not.
578 // Either all method id's must be manually assigned or all of them must not.
579 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
580 set<int> usedIds;
581 interface_item_type* item = first_item;
582 bool hasUnassignedIds = false;
583 bool hasAssignedIds = false;
584 while (item != NULL) {
585 if (item->item_type == METHOD_TYPE) {
586 method_type* method_item = (method_type*)item;
587 if (method_item->hasId) {
588 hasAssignedIds = true;
589 method_item->assigned_id = atoi(method_item->id.data);
590 // Ensure that the user set id is not duplicated.
591 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
592 // We found a duplicate id, so throw an error.
593 fprintf(stderr,
594 "%s:%d Found duplicate method id (%d) for method: %s\n",
595 filename, method_item->id.lineno,
596 method_item->assigned_id, method_item->name.data);
597 return 1;
598 }
599 // Ensure that the user set id is within the appropriate limits
Christopher Wileyf690be52015-09-14 15:19:10 -0700600 if (method_item->assigned_id < kMinUserSetMethodId ||
601 method_item->assigned_id > kMaxUserSetMethodId) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800602 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
603 filename, method_item->id.lineno,
604 method_item->assigned_id, method_item->name.data);
605 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
Christopher Wileyf690be52015-09-14 15:19:10 -0700606 kMinUserSetMethodId, kMaxUserSetMethodId);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800607 return 1;
608 }
609 usedIds.insert(method_item->assigned_id);
610 } else {
611 hasUnassignedIds = true;
612 }
613 if (hasAssignedIds && hasUnassignedIds) {
614 fprintf(stderr,
615 "%s: You must either assign id's to all methods or to none of them.\n",
616 filename);
617 return 1;
618 }
619 }
620 item = item->next;
621 }
622
623 // In the case that all methods have unassigned id's, set a unique id for them.
624 if (hasUnassignedIds) {
625 int newId = 0;
626 item = first_item;
627 while (item != NULL) {
628 if (item->item_type == METHOD_TYPE) {
629 method_type* method_item = (method_type*)item;
630 method_item->assigned_id = newId++;
631 }
632 item = item->next;
633 }
634 }
635
636 // success
637 return 0;
638}
639
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700640int load_and_validate_aidl(const std::vector<std::string> preprocessed_files,
641 const std::vector<std::string> import_paths,
642 const std::string& input_file_name,
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700643 TypeNamespace* types,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700644 interface_type** returned_interface,
645 import_info** returned_imports) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700646 int err = 0;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800647
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700648 set_import_paths(import_paths);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800649
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700650 // import the preprocessed file
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700651 for (const string& s : preprocessed_files) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700652 err |= parse_preprocessed_file(s, types);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700653 }
654 if (err != 0) {
655 return err;
656 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800657
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700658 // parse the input file
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700659 Parser p{input_file_name};
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700660 if (!p.OpenFileFromDisk() || !p.RunParser()) {
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700661 return 1;
662 }
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700663 document_item_type* parsed_doc = p.GetDocument();
664 // We could in theory declare parcelables in the same file as the interface.
665 // In practice, those parcelables would have to have the same name as
666 // the interface, since this was originally written to support Java, with its
667 // packages and names that correspond to file system structure.
668 // Since we can't have two distinct classes with the same name and package,
669 // we can't actually declare parcelables in the same file.
670 if (parsed_doc == nullptr ||
671 parsed_doc->item_type != INTERFACE_TYPE_BINDER ||
672 parsed_doc->next != nullptr) {
673 cerr << "aidl expects exactly one interface per input file";
674 err |= 1;
675 }
676 interface_type* interface = (interface_type*)parsed_doc;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700677 err |= check_filename(input_file_name.c_str(),
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700678 interface->package, &interface->name);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800679
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700680 // parse the imports of the input file
681 for (import_info* import = p.GetImports(); import; import = import->next) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700682 if (types->Find(import->neededClass) != NULL) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700683 continue;
684 }
685 import->filename = find_import_file(import->neededClass);
686 if (!import->filename) {
687 cerr << import->from << ":" << import->statement.lineno
688 << ": couldn't find import for class "
689 << import->neededClass << endl;
690 err |= 1;
691 continue;
692 }
693 Parser p{import->filename};
694 if (!p.OpenFileFromDisk() || !p.RunParser() || p.GetDocument() == nullptr) {
695 cerr << "error while parsing import for class "
696 << import->neededClass << endl;
697 err |= 1;
698 continue;
699 }
700 import->doc = p.GetDocument();
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700701 err |= check_filenames(import->filename, import->doc);
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700702 }
703 if (err != 0) {
704 return err;
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700705 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800706
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700707 // gather the types that have been declared
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700708 if (!gather_types(input_file_name.c_str(), parsed_doc, types)) {
709 err |= 1;
710 }
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700711 for (import_info* import = p.GetImports(); import; import = import->next) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700712 if (!gather_types(import->filename, import->doc, types)) {
713 err |= 1;
714 }
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700715 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800716
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700717 // check the referenced types in parsed_doc to make sure we've imported them
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700718 err |= check_types(input_file_name.c_str(), parsed_doc, types);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800719
Adam Lesinskiffa16862014-01-23 18:17:42 -0800720
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700721 // assign method ids and validate.
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700722 err |= check_and_assign_method_ids(input_file_name.c_str(),
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700723 interface->interface_items);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800724
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700725 // after this, there shouldn't be any more errors because of the
726 // input.
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700727 if (err != 0) {
728 return err;
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700729 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800730
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700731 *returned_interface = interface;
732 *returned_imports = p.GetImports();
733 return 0;
734}
735
736} // namespace
737
738int compile_aidl_to_cpp(const CppOptions& options) {
739 interface_type* interface = nullptr;
740 import_info* imports = nullptr;
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700741 register_base_types();
742 JavaTypeNamespace* types = &NAMES;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700743 int err = load_and_validate_aidl(std::vector<std::string>{},
744 options.ImportPaths(),
745 options.InputFileName(),
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700746 types,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700747 &interface,
748 &imports);
749 if (err != 0) {
750 return err;
751 }
752
753 // TODO(wiley) b/23600457 generate a dependency file if requested with -b
754
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700755 return (GenerateCpp(options, interface)) ? 0 : 1;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700756}
757
758int compile_aidl_to_java(const JavaOptions& options) {
759 interface_type* interface = nullptr;
760 import_info* imports = nullptr;
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700761 register_base_types();
762 JavaTypeNamespace* types = &NAMES;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700763 int err = load_and_validate_aidl(options.preprocessed_files_,
764 options.import_paths_,
765 options.input_file_name_,
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700766 types,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700767 &interface,
768 &imports);
769 if (err != 0) {
770 return err;
771 }
772 document_item_type* parsed_doc = (document_item_type*)interface;
773
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700774 string output_file_name = options.output_file_name_;
775 // if needed, generate the output file name from the base folder
776 if (output_file_name.length() == 0 &&
777 options.output_base_folder_.length() > 0) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700778 output_file_name = generate_outputFileName(options, parsed_doc);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700779 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800780
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700781 // if we were asked to, generate a make dependency file
782 // unless it's a parcelable *and* it's supposed to fail on parcelable
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700783 if (options.auto_dep_file_ || options.dep_file_name_ != "") {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800784 // make sure the folders of the output file all exists
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700785 check_outputFilePath(output_file_name);
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700786 generate_dep_file(options, parsed_doc, imports);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700787 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800788
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700789 // make sure the folders of the output file all exists
790 check_outputFilePath(output_file_name);
791
792 err = generate_java(output_file_name, options.input_file_name_.c_str(),
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700793 interface, types);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700794
795 return err;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800796}
797
Christopher Wileyf690be52015-09-14 15:19:10 -0700798int preprocess_aidl(const JavaOptions& options) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800799 vector<string> lines;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800800
801 // read files
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700802 int N = options.files_to_preprocess_.size();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800803 for (int i=0; i<N; i++) {
Casey Dahline2507492015-09-14 17:11:20 -0700804 Parser p{options.files_to_preprocess_[i]};
Casey Dahlin99801812015-09-15 18:19:25 -0700805 if (!p.OpenFileFromDisk())
Casey Dahline2507492015-09-14 17:11:20 -0700806 return 1;
Casey Dahlin99801812015-09-15 18:19:25 -0700807 if (!p.RunParser())
808 return 1;
Casey Dahline2507492015-09-14 17:11:20 -0700809 document_item_type* doc = p.GetDocument();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800810 string line;
811 if (doc->item_type == USER_DATA_TYPE) {
812 user_data_type* parcelable = (user_data_type*)doc;
Casey Dahlin88868fc2015-09-01 13:21:26 -0700813 if (parcelable->parcelable) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800814 line = "parcelable ";
815 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800816 if (parcelable->package) {
817 line += parcelable->package;
818 line += '.';
819 }
820 line += parcelable->name.data;
821 } else {
822 line = "interface ";
823 interface_type* iface = (interface_type*)doc;
824 if (iface->package) {
825 line += iface->package;
826 line += '.';
827 }
828 line += iface->name.data;
829 }
830 line += ";\n";
831 lines.push_back(line);
832 }
833
834 // write preprocessed file
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700835 int fd = open( options.output_file_name_.c_str(),
Adam Lesinskiffa16862014-01-23 18:17:42 -0800836 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
Elliott Hughes549b6e22015-08-17 12:41:46 -0700837#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800838 _S_IREAD|_S_IWRITE);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700839#else
Adam Lesinskiffa16862014-01-23 18:17:42 -0800840 S_IRUSR|S_IWUSR|S_IRGRP);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700841#endif
Adam Lesinskiffa16862014-01-23 18:17:42 -0800842 if (fd == -1) {
843 fprintf(stderr, "aidl: could not open file for write: %s\n",
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700844 options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800845 return 1;
846 }
847
848 N = lines.size();
849 for (int i=0; i<N; i++) {
850 const string& s = lines[i];
851 int len = s.length();
852 if (len != write(fd, s.c_str(), len)) {
853 fprintf(stderr, "aidl: error writing to file %s\n",
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700854 options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800855 close(fd);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700856 unlink(options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800857 return 1;
858 }
859 }
860
861 close(fd);
862 return 0;
863}
Christopher Wileyfdeb0f42015-09-11 15:38:22 -0700864
865} // namespace android
866} // namespace aidl