blob: 1f173164679cde8c358b8320459ebdfae0cc55e2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001//
2// Copyright 2006 The Android Open Source Project
3//
4
5#include "AaptAssets.h"
Dianne Hackborne6b68032011-10-13 16:26:02 -07006#include "ResourceFilter.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007#include "Main.h"
8
9#include <utils/misc.h>
10#include <utils/SortedVector.h>
11
12#include <ctype.h>
13#include <dirent.h>
14#include <errno.h>
15
16static const char* kDefaultLocale = "default";
17static const char* kWildcardName = "any";
18static const char* kAssetDir = "assets";
19static const char* kResourceDir = "res";
Dianne Hackborne6b68032011-10-13 16:26:02 -070020static const char* kValuesDir = "values";
21static const char* kMipmapDir = "mipmap";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022static const char* kInvalidChars = "/\\:";
23static const size_t kMaxAssetFileName = 100;
24
25static const String8 kResString(kResourceDir);
26
27/*
28 * Names of asset files must meet the following criteria:
29 *
30 * - the filename length must be less than kMaxAssetFileName bytes long
31 * (and can't be empty)
32 * - all characters must be 7-bit printable ASCII
33 * - none of { '/' '\\' ':' }
34 *
35 * Pass in just the filename, not the full path.
36 */
37static bool validateFileName(const char* fileName)
38{
39 const char* cp = fileName;
40 size_t len = 0;
41
42 while (*cp != '\0') {
43 if ((*cp & 0x80) != 0)
44 return false; // reject high ASCII
45 if (*cp < 0x20 || *cp >= 0x7f)
46 return false; // reject control chars and 0x7f
47 if (strchr(kInvalidChars, *cp) != NULL)
48 return false; // reject path sep chars
49 cp++;
50 len++;
51 }
52
53 if (len < 1 || len > kMaxAssetFileName)
54 return false; // reject empty or too long
55
56 return true;
57}
58
Raphael Moll6c255a32012-05-07 16:16:46 -070059// The default to use if no other ignore pattern is defined.
60const char * const gDefaultIgnoreAssets =
Tor Norbyee0219c82012-06-04 10:38:13 -070061 "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~";
Raphael Moll6c255a32012-05-07 16:16:46 -070062// The ignore pattern that can be passed via --ignore-assets in Main.cpp
63const char * gUserIgnoreAssets = NULL;
64
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065static bool isHidden(const char *root, const char *path)
66{
Raphael Moll6c255a32012-05-07 16:16:46 -070067 // Patterns syntax:
68 // - Delimiter is :
69 // - Entry can start with the flag ! to avoid printing a warning
70 // about the file being ignored.
71 // - Entry can have the flag "<dir>" to match only directories
72 // or <file> to match only files. Default is to match both.
73 // - Entry can be a simplified glob "<prefix>*" or "*<suffix>"
74 // where prefix/suffix must have at least 1 character (so that
75 // we don't match a '*' catch-all pattern.)
76 // - The special filenames "." and ".." are always ignored.
77 // - Otherwise the full string is matched.
78 // - match is not case-sensitive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Raphael Moll6c255a32012-05-07 16:16:46 -070080 if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 }
83
Raphael Moll6c255a32012-05-07 16:16:46 -070084 const char *delim = ":";
85 const char *p = gUserIgnoreAssets;
86 if (!p || !p[0]) {
87 p = getenv("ANDROID_AAPT_IGNORE");
88 }
89 if (!p || !p[0]) {
90 p = gDefaultIgnoreAssets;
91 }
92 char *patterns = strdup(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
Raphael Moll6c255a32012-05-07 16:16:46 -070094 bool ignore = false;
95 bool chatty = true;
96 char *matchedPattern = NULL;
97
98 String8 fullPath(root);
99 fullPath.appendPath(path);
100 FileType type = getFileType(fullPath);
101
102 int plen = strlen(path);
103
104 // Note: we don't have strtok_r under mingw.
105 for(char *token = strtok(patterns, delim);
106 !ignore && token != NULL;
107 token = strtok(NULL, delim)) {
108 chatty = token[0] != '!';
109 if (!chatty) token++; // skip !
110 if (strncasecmp(token, "<dir>" , 5) == 0) {
111 if (type != kFileTypeDirectory) continue;
112 token += 5;
113 }
114 if (strncasecmp(token, "<file>", 6) == 0) {
115 if (type != kFileTypeRegular) continue;
116 token += 6;
117 }
118
119 matchedPattern = token;
120 int n = strlen(token);
121
122 if (token[0] == '*') {
123 // Match *suffix
124 token++;
Ying Wang996b0732012-05-22 11:24:22 -0700125 n--;
Raphael Moll6c255a32012-05-07 16:16:46 -0700126 if (n <= plen) {
127 ignore = strncasecmp(token, path + plen - n, n) == 0;
128 }
129 } else if (n > 1 && token[n - 1] == '*') {
130 // Match prefix*
131 ignore = strncasecmp(token, path, n - 1) == 0;
132 } else {
133 ignore = strcasecmp(token, path) == 0;
134 }
135 }
136
137 if (ignore && chatty) {
138 fprintf(stderr, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
139 type == kFileTypeDirectory ? "dir" : "file",
140 path,
141 matchedPattern ? matchedPattern : "");
142 }
143
144 free(patterns);
145 return ignore;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146}
147
148// =========================================================================
149// =========================================================================
150// =========================================================================
151
Narayan Kamath788fa412014-01-21 15:32:36 +0000152/* static */ void AaptLocaleValue::splitAndLowerCase(const char* const chars,
153 Vector<String8>* parts, const char separator) {
154 const char *p = chars;
155 const char *q;
156 while (NULL != (q = strchr(p, separator))) {
157 String8 val(p, q - p);
158 val.toLower();
159 parts->add(val);
160 p = q+1;
161 }
162
163 if (p < chars + strlen(chars)) {
164 String8 val(p);
165 val.toLower();
166 parts->add(val);
167 }
168}
169
170/* static */
171inline bool isAlpha(const String8& string) {
172 const size_t length = string.length();
173 for (size_t i = 0; i < length; ++i) {
174 if (!isalpha(string[i])) {
175 return false;
176 }
177 }
178
179 return true;
180}
181
182/* static */
183inline bool isNumber(const String8& string) {
184 const size_t length = string.length();
185 for (size_t i = 0; i < length; ++i) {
186 if (!isdigit(string[i])) {
187 return false;
188 }
189 }
190
191 return true;
192}
193
194void AaptLocaleValue::setLanguage(const char* languageChars) {
195 size_t i = 0;
196 while ((*languageChars) != '\0') {
197 language[i++] = tolower(*languageChars);
198 languageChars++;
199 }
200}
201
202void AaptLocaleValue::setRegion(const char* regionChars) {
203 size_t i = 0;
204 while ((*regionChars) != '\0') {
205 region[i++] = toupper(*regionChars);
206 regionChars++;
207 }
208}
209
210void AaptLocaleValue::setScript(const char* scriptChars) {
211 size_t i = 0;
212 while ((*scriptChars) != '\0') {
213 if (i == 0) {
214 script[i++] = toupper(*scriptChars);
215 } else {
216 script[i++] = tolower(*scriptChars);
217 }
218 scriptChars++;
219 }
220}
221
222void AaptLocaleValue::setVariant(const char* variantChars) {
223 size_t i = 0;
224 while ((*variantChars) != '\0') {
225 variant[i++] = *variantChars;
226 variantChars++;
227 }
228}
229
230bool AaptLocaleValue::initFromFilterString(const String8& str) {
231 // A locale (as specified in the filter) is an underscore separated name such
232 // as "en_US", "en_Latn_US", or "en_US_POSIX".
233 Vector<String8> parts;
234 splitAndLowerCase(str.string(), &parts, '_');
235
236 const int numTags = parts.size();
237 bool valid = false;
238 if (numTags >= 1) {
239 const String8& lang = parts[0];
240 if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
241 setLanguage(lang.string());
242 valid = true;
243 }
244 }
245
246 if (!valid || numTags == 1) {
247 return valid;
248 }
249
250 // At this point, valid == true && numTags > 1.
251 const String8& part2 = parts[1];
252 if ((part2.length() == 2 && isAlpha(part2)) ||
253 (part2.length() == 3 && isNumber(part2))) {
254 setRegion(part2.string());
255 } else if (part2.length() == 4 && isAlpha(part2)) {
256 setScript(part2.string());
257 } else if (part2.length() >= 5 && part2.length() <= 8) {
258 setVariant(part2.string());
259 } else {
260 valid = false;
261 }
262
263 if (!valid || numTags == 2) {
264 return valid;
265 }
266
267 // At this point, valid == true && numTags > 1.
268 const String8& part3 = parts[2];
269 if (((part3.length() == 2 && isAlpha(part3)) ||
270 (part3.length() == 3 && isNumber(part3))) && script[0]) {
271 setRegion(part3.string());
272 } else if (part3.length() >= 5 && part3.length() <= 8) {
273 setVariant(part3.string());
274 } else {
275 valid = false;
276 }
277
278 if (!valid || numTags == 3) {
279 return valid;
280 }
281
282 const String8& part4 = parts[3];
283 if (part4.length() >= 5 && part4.length() <= 8) {
284 setVariant(part4.string());
285 } else {
286 valid = false;
287 }
288
289 if (!valid || numTags > 4) {
290 return false;
291 }
292
293 return true;
294}
295
296int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int startIndex) {
297 const int size = parts.size();
298 int currentIndex = startIndex;
299
300 String8 part = parts[currentIndex];
301 if (part[0] == 'b' && part[1] == '+') {
302 // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
303 // except that the separator is "+" and not "-".
304 Vector<String8> subtags;
305 AaptLocaleValue::splitAndLowerCase(part.string(), &subtags, '+');
306 subtags.removeItemsAt(0);
307 if (subtags.size() == 1) {
308 setLanguage(subtags[0]);
309 } else if (subtags.size() == 2) {
310 setLanguage(subtags[0]);
311
312 // The second tag can either be a region, a variant or a script.
313 switch (subtags[1].size()) {
314 case 2:
315 case 3:
316 setRegion(subtags[1]);
317 break;
318 case 4:
319 setScript(subtags[1]);
320 break;
321 case 5:
322 case 6:
323 case 7:
324 case 8:
325 setVariant(subtags[1]);
326 break;
327 default:
328 fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n",
329 part.string());
330 return -1;
331 }
332 } else if (subtags.size() == 3) {
333 // The language is always the first subtag.
334 setLanguage(subtags[0]);
335
336 // The second subtag can either be a script or a region code.
337 // If its size is 4, it's a script code, else it's a region code.
338 bool hasRegion = false;
339 if (subtags[1].size() == 4) {
340 setScript(subtags[1]);
341 } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
342 setRegion(subtags[1]);
343 hasRegion = true;
344 } else {
345 fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n", part.string());
346 return -1;
347 }
348
349 // The third tag can either be a region code (if the second tag was
350 // a script), else a variant code.
351 if (subtags[2].size() > 4) {
352 setVariant(subtags[2]);
353 } else {
354 setRegion(subtags[2]);
355 }
356 } else if (subtags.size() == 4) {
357 setLanguage(subtags[0]);
358 setScript(subtags[1]);
359 setRegion(subtags[2]);
360 setVariant(subtags[3]);
361 } else {
362 fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name: %s\n", part.string());
363 return -1;
364 }
365
366 return ++currentIndex;
367 } else {
368 if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
369 setLanguage(part);
370 if (++currentIndex == size) {
371 return size;
372 }
373 } else {
374 return currentIndex;
375 }
376
377 part = parts[currentIndex];
378 if (part.string()[0] == 'r' && part.length() == 3) {
379 setRegion(part.string() + 1);
380 if (++currentIndex == size) {
381 return size;
382 }
383 }
384 }
385
386 return currentIndex;
387}
388
389
390String8 AaptLocaleValue::toDirName() const {
391 String8 dirName("");
392 if (language[0]) {
393 dirName += language;
394 } else {
395 return dirName;
396 }
397
398 if (script[0]) {
399 dirName += "-s";
400 dirName += script;
401 }
402
403 if (region[0]) {
404 dirName += "-r";
405 dirName += region;
406 }
407
408 if (variant[0]) {
409 dirName += "-v";
410 dirName += variant;
411 }
412
413 return dirName;
414}
415
416void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
417 config.unpackLanguage(language);
418 config.unpackRegion(region);
419 if (config.localeScript[0]) {
420 memcpy(script, config.localeScript, sizeof(config.localeScript));
421 }
422
423 if (config.localeVariant[0]) {
424 memcpy(variant, config.localeVariant, sizeof(config.localeVariant));
425 }
426}
427
428void AaptLocaleValue::writeTo(ResTable_config* out) const {
429 out->packLanguage(language);
430 out->packRegion(region);
431
432 if (script[0]) {
433 memcpy(out->localeScript, script, sizeof(out->localeScript));
434 }
435
436 if (variant[0]) {
437 memcpy(out->localeVariant, variant, sizeof(out->localeVariant));
438 }
439}
440
441
442/* static */ bool
443AaptGroupEntry::parseFilterNamePart(const String8& part, int* axis, AxisValue* value)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444{
445 ResTable_config config;
Narayan Kamath788fa412014-01-21 15:32:36 +0000446 memset(&config, 0, sizeof(ResTable_config));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447
448 // IMSI - MCC
449 if (getMccName(part.string(), &config)) {
450 *axis = AXIS_MCC;
Narayan Kamath788fa412014-01-21 15:32:36 +0000451 value->intValue = config.mcc;
452 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 }
454
455 // IMSI - MNC
456 if (getMncName(part.string(), &config)) {
457 *axis = AXIS_MNC;
Narayan Kamath788fa412014-01-21 15:32:36 +0000458 value->intValue = config.mnc;
459 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 }
461
462 // locale - language
Narayan Kamath788fa412014-01-21 15:32:36 +0000463 if (value->localeValue.initFromFilterString(part)) {
464 *axis = AXIS_LOCALE;
465 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 }
467
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700468 // layout direction
469 if (getLayoutDirectionName(part.string(), &config)) {
470 *axis = AXIS_LAYOUTDIR;
Narayan Kamath788fa412014-01-21 15:32:36 +0000471 value->intValue = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
472 return true;
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700473 }
474
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700475 // smallest screen dp width
476 if (getSmallestScreenWidthDpName(part.string(), &config)) {
477 *axis = AXIS_SMALLESTSCREENWIDTHDP;
Narayan Kamath788fa412014-01-21 15:32:36 +0000478 value->intValue = config.smallestScreenWidthDp;
479 return true;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700480 }
481
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700482 // screen dp width
483 if (getScreenWidthDpName(part.string(), &config)) {
484 *axis = AXIS_SCREENWIDTHDP;
Narayan Kamath788fa412014-01-21 15:32:36 +0000485 value->intValue = config.screenWidthDp;
486 return true;
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700487 }
488
489 // screen dp height
490 if (getScreenHeightDpName(part.string(), &config)) {
491 *axis = AXIS_SCREENHEIGHTDP;
Narayan Kamath788fa412014-01-21 15:32:36 +0000492 value->intValue = config.screenHeightDp;
493 return true;
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700494 }
495
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700496 // screen layout size
497 if (getScreenLayoutSizeName(part.string(), &config)) {
498 *axis = AXIS_SCREENLAYOUTSIZE;
Narayan Kamath788fa412014-01-21 15:32:36 +0000499 value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
500 return true;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700501 }
502
503 // screen layout long
504 if (getScreenLayoutLongName(part.string(), &config)) {
505 *axis = AXIS_SCREENLAYOUTLONG;
Narayan Kamath788fa412014-01-21 15:32:36 +0000506 value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
507 return true;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700508 }
509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 // orientation
511 if (getOrientationName(part.string(), &config)) {
512 *axis = AXIS_ORIENTATION;
Narayan Kamath788fa412014-01-21 15:32:36 +0000513 value->intValue = config.orientation;
514 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 }
516
Tobias Haamel27b28b32010-02-09 23:09:17 +0100517 // ui mode type
518 if (getUiModeTypeName(part.string(), &config)) {
519 *axis = AXIS_UIMODETYPE;
Narayan Kamath788fa412014-01-21 15:32:36 +0000520 value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
521 return true;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100522 }
523
524 // ui mode night
525 if (getUiModeNightName(part.string(), &config)) {
526 *axis = AXIS_UIMODENIGHT;
Narayan Kamath788fa412014-01-21 15:32:36 +0000527 value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
528 return true;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100529 }
530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 // density
532 if (getDensityName(part.string(), &config)) {
533 *axis = AXIS_DENSITY;
Narayan Kamath788fa412014-01-21 15:32:36 +0000534 value->intValue = config.density;
535 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 }
537
538 // touchscreen
539 if (getTouchscreenName(part.string(), &config)) {
540 *axis = AXIS_TOUCHSCREEN;
Narayan Kamath788fa412014-01-21 15:32:36 +0000541 value->intValue = config.touchscreen;
542 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 }
544
545 // keyboard hidden
546 if (getKeysHiddenName(part.string(), &config)) {
547 *axis = AXIS_KEYSHIDDEN;
Narayan Kamath788fa412014-01-21 15:32:36 +0000548 value->intValue = config.inputFlags;
549 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 }
551
552 // keyboard
553 if (getKeyboardName(part.string(), &config)) {
554 *axis = AXIS_KEYBOARD;
Narayan Kamath788fa412014-01-21 15:32:36 +0000555 value->intValue = config.keyboard;
556 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700559 // navigation hidden
560 if (getNavHiddenName(part.string(), &config)) {
561 *axis = AXIS_NAVHIDDEN;
Narayan Kamath788fa412014-01-21 15:32:36 +0000562 value->intValue = config.inputFlags;
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700563 return 0;
564 }
565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 // navigation
567 if (getNavigationName(part.string(), &config)) {
568 *axis = AXIS_NAVIGATION;
Narayan Kamath788fa412014-01-21 15:32:36 +0000569 value->intValue = config.navigation;
570 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 }
572
573 // screen size
574 if (getScreenSizeName(part.string(), &config)) {
575 *axis = AXIS_SCREENSIZE;
Narayan Kamath788fa412014-01-21 15:32:36 +0000576 value->intValue = config.screenSize;
577 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 }
579
580 // version
581 if (getVersionName(part.string(), &config)) {
582 *axis = AXIS_VERSION;
Narayan Kamath788fa412014-01-21 15:32:36 +0000583 value->intValue = config.version;
584 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 }
586
Narayan Kamath788fa412014-01-21 15:32:36 +0000587 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588}
589
Narayan Kamath788fa412014-01-21 15:32:36 +0000590AxisValue
Dianne Hackborne6b68032011-10-13 16:26:02 -0700591AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
592{
Narayan Kamath788fa412014-01-21 15:32:36 +0000593 AxisValue value;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700594 switch (axis) {
595 case AXIS_MCC:
Narayan Kamath788fa412014-01-21 15:32:36 +0000596 value.intValue = config.mcc;
597 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700598 case AXIS_MNC:
Narayan Kamath788fa412014-01-21 15:32:36 +0000599 value.intValue = config.mnc;
600 break;
601 case AXIS_LOCALE:
602 value.localeValue.initFromResTable(config);
603 break;
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700604 case AXIS_LAYOUTDIR:
Narayan Kamath788fa412014-01-21 15:32:36 +0000605 value.intValue = config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
606 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700607 case AXIS_SCREENLAYOUTSIZE:
Narayan Kamath788fa412014-01-21 15:32:36 +0000608 value.intValue = config.screenLayout&ResTable_config::MASK_SCREENSIZE;
609 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700610 case AXIS_ORIENTATION:
Narayan Kamath788fa412014-01-21 15:32:36 +0000611 value.intValue = config.orientation;
612 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700613 case AXIS_UIMODETYPE:
Narayan Kamath788fa412014-01-21 15:32:36 +0000614 value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
615 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700616 case AXIS_UIMODENIGHT:
Narayan Kamath788fa412014-01-21 15:32:36 +0000617 value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
618 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700619 case AXIS_DENSITY:
Narayan Kamath788fa412014-01-21 15:32:36 +0000620 value.intValue = config.density;
621 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700622 case AXIS_TOUCHSCREEN:
Narayan Kamath788fa412014-01-21 15:32:36 +0000623 value.intValue = config.touchscreen;
624 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700625 case AXIS_KEYSHIDDEN:
Narayan Kamath788fa412014-01-21 15:32:36 +0000626 value.intValue = config.inputFlags;
627 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700628 case AXIS_KEYBOARD:
Narayan Kamath788fa412014-01-21 15:32:36 +0000629 value.intValue = config.keyboard;
630 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700631 case AXIS_NAVIGATION:
Narayan Kamath788fa412014-01-21 15:32:36 +0000632 value.intValue = config.navigation;
633 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700634 case AXIS_SCREENSIZE:
Narayan Kamath788fa412014-01-21 15:32:36 +0000635 value.intValue = config.screenSize;
636 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700637 case AXIS_SMALLESTSCREENWIDTHDP:
Narayan Kamath788fa412014-01-21 15:32:36 +0000638 value.intValue = config.smallestScreenWidthDp;
639 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700640 case AXIS_SCREENWIDTHDP:
Narayan Kamath788fa412014-01-21 15:32:36 +0000641 value.intValue = config.screenWidthDp;
642 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700643 case AXIS_SCREENHEIGHTDP:
Narayan Kamath788fa412014-01-21 15:32:36 +0000644 value.intValue = config.screenHeightDp;
645 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700646 case AXIS_VERSION:
Narayan Kamath788fa412014-01-21 15:32:36 +0000647 value.intValue = config.version;
648 break;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700649 }
Narayan Kamath788fa412014-01-21 15:32:36 +0000650
651 return value;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700652}
653
654bool
655AaptGroupEntry::configSameExcept(const ResTable_config& config,
656 const ResTable_config& otherConfig, int axis)
657{
658 for (int i=AXIS_START; i<=AXIS_END; i++) {
659 if (i == axis) {
660 continue;
661 }
662 if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
663 return false;
664 }
665 }
666 return true;
667}
668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669bool
670AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
671{
Dianne Hackborne6b68032011-10-13 16:26:02 -0700672 mParamsChanged = true;
673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 Vector<String8> parts;
Narayan Kamath788fa412014-01-21 15:32:36 +0000675 AaptLocaleValue::splitAndLowerCase(dir, &parts, '-');
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676
Narayan Kamath788fa412014-01-21 15:32:36 +0000677 String8 mcc, mnc, layoutsize, layoutlong, orient, den;
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700678 String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700679 String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680
Narayan Kamath788fa412014-01-21 15:32:36 +0000681 AaptLocaleValue locale;
682 int numLocaleComponents = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683
684 const int N = parts.size();
685 int index = 0;
686 String8 part = parts[index];
687
688 // resource type
689 if (!isValidResourceType(part)) {
690 return false;
691 }
692 *resType = part;
693
694 index++;
695 if (index == N) {
696 goto success;
697 }
698 part = parts[index];
699
700 // imsi - mcc
701 if (getMccName(part.string())) {
702 mcc = part;
703
704 index++;
705 if (index == N) {
706 goto success;
707 }
708 part = parts[index];
709 } else {
710 //printf("not mcc: %s\n", part.string());
711 }
712
713 // imsi - mnc
714 if (getMncName(part.string())) {
715 mnc = part;
716
717 index++;
718 if (index == N) {
719 goto success;
720 }
721 part = parts[index];
722 } else {
Narayan Kamath788fa412014-01-21 15:32:36 +0000723 //printf("not mnc: %s\n", part.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
725
Narayan Kamath788fa412014-01-21 15:32:36 +0000726 index = locale.initFromDirName(parts, index);
727 if (index == -1) {
728 return false;
729 }
730 if (index >= N){
731 goto success;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733
Narayan Kamath788fa412014-01-21 15:32:36 +0000734 part = parts[index];
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700735 if (getLayoutDirectionName(part.string())) {
736 layoutDir = part;
737
738 index++;
739 if (index == N) {
740 goto success;
741 }
742 part = parts[index];
743 } else {
744 //printf("not layout direction: %s\n", part.string());
745 }
746
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700747 if (getSmallestScreenWidthDpName(part.string())) {
748 smallestwidthdp = part;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700749
750 index++;
751 if (index == N) {
752 goto success;
753 }
754 part = parts[index];
755 } else {
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700756 //printf("not smallest screen width dp: %s\n", part.string());
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700757 }
758
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700759 if (getScreenWidthDpName(part.string())) {
760 widthdp = part;
761
762 index++;
763 if (index == N) {
764 goto success;
765 }
766 part = parts[index];
767 } else {
768 //printf("not screen width dp: %s\n", part.string());
769 }
770
771 if (getScreenHeightDpName(part.string())) {
772 heightdp = part;
773
774 index++;
775 if (index == N) {
776 goto success;
777 }
778 part = parts[index];
779 } else {
780 //printf("not screen height dp: %s\n", part.string());
781 }
782
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700783 if (getScreenLayoutSizeName(part.string())) {
784 layoutsize = part;
785
786 index++;
787 if (index == N) {
788 goto success;
789 }
790 part = parts[index];
791 } else {
792 //printf("not screen layout size: %s\n", part.string());
793 }
794
795 if (getScreenLayoutLongName(part.string())) {
796 layoutlong = part;
797
798 index++;
799 if (index == N) {
800 goto success;
801 }
802 part = parts[index];
803 } else {
804 //printf("not screen layout long: %s\n", part.string());
805 }
806
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 // orientation
808 if (getOrientationName(part.string())) {
809 orient = part;
810
811 index++;
812 if (index == N) {
813 goto success;
814 }
815 part = parts[index];
816 } else {
817 //printf("not orientation: %s\n", part.string());
818 }
819
Tobias Haamel27b28b32010-02-09 23:09:17 +0100820 // ui mode type
821 if (getUiModeTypeName(part.string())) {
822 uiModeType = part;
823
824 index++;
825 if (index == N) {
826 goto success;
827 }
828 part = parts[index];
829 } else {
830 //printf("not ui mode type: %s\n", part.string());
831 }
832
833 // ui mode night
834 if (getUiModeNightName(part.string())) {
835 uiModeNight = part;
836
837 index++;
838 if (index == N) {
839 goto success;
840 }
841 part = parts[index];
842 } else {
843 //printf("not ui mode night: %s\n", part.string());
844 }
845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 // density
847 if (getDensityName(part.string())) {
848 den = part;
849
850 index++;
851 if (index == N) {
852 goto success;
853 }
854 part = parts[index];
855 } else {
856 //printf("not density: %s\n", part.string());
857 }
858
859 // touchscreen
860 if (getTouchscreenName(part.string())) {
861 touch = part;
862
863 index++;
864 if (index == N) {
865 goto success;
866 }
867 part = parts[index];
868 } else {
869 //printf("not touchscreen: %s\n", part.string());
870 }
871
872 // keyboard hidden
873 if (getKeysHiddenName(part.string())) {
874 keysHidden = part;
875
876 index++;
877 if (index == N) {
878 goto success;
879 }
880 part = parts[index];
881 } else {
882 //printf("not keysHidden: %s\n", part.string());
883 }
884
885 // keyboard
886 if (getKeyboardName(part.string())) {
887 key = part;
888
889 index++;
890 if (index == N) {
891 goto success;
892 }
893 part = parts[index];
894 } else {
895 //printf("not keyboard: %s\n", part.string());
896 }
897
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700898 // navigation hidden
899 if (getNavHiddenName(part.string())) {
900 navHidden = part;
901
902 index++;
903 if (index == N) {
904 goto success;
905 }
906 part = parts[index];
907 } else {
908 //printf("not navHidden: %s\n", part.string());
909 }
910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 if (getNavigationName(part.string())) {
912 nav = part;
913
914 index++;
915 if (index == N) {
916 goto success;
917 }
918 part = parts[index];
919 } else {
920 //printf("not navigation: %s\n", part.string());
921 }
922
923 if (getScreenSizeName(part.string())) {
924 size = part;
925
926 index++;
927 if (index == N) {
928 goto success;
929 }
930 part = parts[index];
931 } else {
932 //printf("not screen size: %s\n", part.string());
933 }
934
935 if (getVersionName(part.string())) {
936 vers = part;
937
938 index++;
939 if (index == N) {
940 goto success;
941 }
942 part = parts[index];
943 } else {
944 //printf("not version: %s\n", part.string());
945 }
946
947 // if there are extra parts, it doesn't match
948 return false;
949
950success:
951 this->mcc = mcc;
952 this->mnc = mnc;
Narayan Kamath788fa412014-01-21 15:32:36 +0000953 this->locale = locale;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700954 this->screenLayoutSize = layoutsize;
955 this->screenLayoutLong = layoutlong;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700956 this->smallestScreenWidthDp = smallestwidthdp;
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700957 this->screenWidthDp = widthdp;
958 this->screenHeightDp = heightdp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 this->orientation = orient;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100960 this->uiModeType = uiModeType;
961 this->uiModeNight = uiModeNight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 this->density = den;
963 this->touchscreen = touch;
964 this->keysHidden = keysHidden;
965 this->keyboard = key;
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700966 this->navHidden = navHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 this->navigation = nav;
968 this->screenSize = size;
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700969 this->layoutDirection = layoutDir;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 this->version = vers;
971
972 // what is this anyway?
973 this->vendor = "";
974
975 return true;
976}
977
978String8
979AaptGroupEntry::toString() const
980{
981 String8 s = this->mcc;
982 s += ",";
983 s += this->mnc;
984 s += ",";
Narayan Kamath788fa412014-01-21 15:32:36 +0000985 s += locale.toDirName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 s += ",";
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700987 s += layoutDirection;
988 s += ",";
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700989 s += smallestScreenWidthDp;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700990 s += ",";
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700991 s += screenWidthDp;
992 s += ",";
993 s += screenHeightDp;
994 s += ",";
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700995 s += screenLayoutSize;
996 s += ",";
997 s += screenLayoutLong;
998 s += ",";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 s += this->orientation;
1000 s += ",";
Tobias Haamel27b28b32010-02-09 23:09:17 +01001001 s += uiModeType;
1002 s += ",";
1003 s += uiModeNight;
1004 s += ",";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 s += density;
1006 s += ",";
1007 s += touchscreen;
1008 s += ",";
1009 s += keysHidden;
1010 s += ",";
1011 s += keyboard;
1012 s += ",";
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001013 s += navHidden;
1014 s += ",";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 s += navigation;
1016 s += ",";
1017 s += screenSize;
1018 s += ",";
1019 s += version;
1020 return s;
1021}
1022
1023String8
1024AaptGroupEntry::toDirName(const String8& resType) const
1025{
1026 String8 s = resType;
1027 if (this->mcc != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001028 if (s.length() > 0) {
1029 s += "-";
1030 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 s += mcc;
1032 }
1033 if (this->mnc != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001034 if (s.length() > 0) {
1035 s += "-";
1036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 s += mnc;
1038 }
Narayan Kamath788fa412014-01-21 15:32:36 +00001039
1040 const String8 localeComponent = locale.toDirName();
1041 if (localeComponent != "") {
1042 if (s.length() > 0) {
1043 s += "-";
1044 }
1045 s += localeComponent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
Narayan Kamath788fa412014-01-21 15:32:36 +00001047
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001048 if (this->layoutDirection != "") {
1049 if (s.length() > 0) {
1050 s += "-";
1051 }
1052 s += layoutDirection;
1053 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001054 if (this->smallestScreenWidthDp != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001055 if (s.length() > 0) {
1056 s += "-";
1057 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001058 s += smallestScreenWidthDp;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001059 }
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001060 if (this->screenWidthDp != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001061 if (s.length() > 0) {
1062 s += "-";
1063 }
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001064 s += screenWidthDp;
1065 }
1066 if (this->screenHeightDp != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001067 if (s.length() > 0) {
1068 s += "-";
1069 }
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001070 s += screenHeightDp;
1071 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001072 if (this->screenLayoutSize != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001073 if (s.length() > 0) {
1074 s += "-";
1075 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001076 s += screenLayoutSize;
1077 }
1078 if (this->screenLayoutLong != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001079 if (s.length() > 0) {
1080 s += "-";
1081 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001082 s += screenLayoutLong;
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 if (this->orientation != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001085 if (s.length() > 0) {
1086 s += "-";
1087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 s += orientation;
1089 }
Tobias Haamel27b28b32010-02-09 23:09:17 +01001090 if (this->uiModeType != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001091 if (s.length() > 0) {
1092 s += "-";
1093 }
Tobias Haamel27b28b32010-02-09 23:09:17 +01001094 s += uiModeType;
1095 }
1096 if (this->uiModeNight != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001097 if (s.length() > 0) {
1098 s += "-";
1099 }
Tobias Haamel27b28b32010-02-09 23:09:17 +01001100 s += uiModeNight;
1101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 if (this->density != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001103 if (s.length() > 0) {
1104 s += "-";
1105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 s += density;
1107 }
1108 if (this->touchscreen != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001109 if (s.length() > 0) {
1110 s += "-";
1111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 s += touchscreen;
1113 }
1114 if (this->keysHidden != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001115 if (s.length() > 0) {
1116 s += "-";
1117 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 s += keysHidden;
1119 }
1120 if (this->keyboard != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001121 if (s.length() > 0) {
1122 s += "-";
1123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 s += keyboard;
1125 }
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001126 if (this->navHidden != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001127 if (s.length() > 0) {
1128 s += "-";
1129 }
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001130 s += navHidden;
1131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 if (this->navigation != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001133 if (s.length() > 0) {
1134 s += "-";
1135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 s += navigation;
1137 }
1138 if (this->screenSize != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001139 if (s.length() > 0) {
1140 s += "-";
1141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 s += screenSize;
1143 }
1144 if (this->version != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001145 if (s.length() > 0) {
1146 s += "-";
1147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 s += version;
1149 }
1150
1151 return s;
1152}
1153
1154bool AaptGroupEntry::getMccName(const char* name,
1155 ResTable_config* out)
1156{
1157 if (strcmp(name, kWildcardName) == 0) {
1158 if (out) out->mcc = 0;
1159 return true;
1160 }
1161 const char* c = name;
1162 if (tolower(*c) != 'm') return false;
1163 c++;
1164 if (tolower(*c) != 'c') return false;
1165 c++;
1166 if (tolower(*c) != 'c') return false;
1167 c++;
1168
1169 const char* val = c;
1170
1171 while (*c >= '0' && *c <= '9') {
1172 c++;
1173 }
1174 if (*c != 0) return false;
1175 if (c-val != 3) return false;
1176
1177 int d = atoi(val);
1178 if (d != 0) {
1179 if (out) out->mcc = d;
1180 return true;
1181 }
1182
1183 return false;
1184}
1185
1186bool AaptGroupEntry::getMncName(const char* name,
1187 ResTable_config* out)
1188{
1189 if (strcmp(name, kWildcardName) == 0) {
1190 if (out) out->mcc = 0;
1191 return true;
1192 }
1193 const char* c = name;
1194 if (tolower(*c) != 'm') return false;
1195 c++;
1196 if (tolower(*c) != 'n') return false;
1197 c++;
1198 if (tolower(*c) != 'c') return false;
1199 c++;
1200
1201 const char* val = c;
1202
1203 while (*c >= '0' && *c <= '9') {
1204 c++;
1205 }
1206 if (*c != 0) return false;
1207 if (c-val == 0 || c-val > 3) return false;
1208
Johan Redestig5ef0b9d2010-11-09 14:13:31 +01001209 if (out) {
1210 out->mnc = atoi(val);
Mattias Petersson1d766b52011-10-07 09:33:52 +02001211 if (out->mnc == 0) {
1212 out->mnc = ACONFIGURATION_MNC_ZERO;
1213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 }
1215
Johan Redestig5ef0b9d2010-11-09 14:13:31 +01001216 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217}
1218
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001219bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
1220{
1221 if (strcmp(name, kWildcardName) == 0) {
1222 if (out) out->screenLayout =
1223 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1224 | ResTable_config::LAYOUTDIR_ANY;
1225 return true;
Fabrice Di Meglio8a802db2012-09-05 13:12:02 -07001226 } else if (strcmp(name, "ldltr") == 0) {
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001227 if (out) out->screenLayout =
1228 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1229 | ResTable_config::LAYOUTDIR_LTR;
1230 return true;
Fabrice Di Meglio8a802db2012-09-05 13:12:02 -07001231 } else if (strcmp(name, "ldrtl") == 0) {
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001232 if (out) out->screenLayout =
1233 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1234 | ResTable_config::LAYOUTDIR_RTL;
1235 return true;
1236 }
1237
1238 return false;
1239}
1240
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001241bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
1242 ResTable_config* out)
1243{
1244 if (strcmp(name, kWildcardName) == 0) {
1245 if (out) out->screenLayout =
1246 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1247 | ResTable_config::SCREENSIZE_ANY;
1248 return true;
1249 } else if (strcmp(name, "small") == 0) {
1250 if (out) out->screenLayout =
1251 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1252 | ResTable_config::SCREENSIZE_SMALL;
1253 return true;
1254 } else if (strcmp(name, "normal") == 0) {
1255 if (out) out->screenLayout =
1256 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1257 | ResTable_config::SCREENSIZE_NORMAL;
1258 return true;
1259 } else if (strcmp(name, "large") == 0) {
1260 if (out) out->screenLayout =
1261 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1262 | ResTable_config::SCREENSIZE_LARGE;
1263 return true;
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001264 } else if (strcmp(name, "xlarge") == 0) {
1265 if (out) out->screenLayout =
1266 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1267 | ResTable_config::SCREENSIZE_XLARGE;
1268 return true;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001269 }
1270
1271 return false;
1272}
1273
1274bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
1275 ResTable_config* out)
1276{
1277 if (strcmp(name, kWildcardName) == 0) {
1278 if (out) out->screenLayout =
1279 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1280 | ResTable_config::SCREENLONG_ANY;
1281 return true;
1282 } else if (strcmp(name, "long") == 0) {
1283 if (out) out->screenLayout =
1284 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1285 | ResTable_config::SCREENLONG_YES;
1286 return true;
1287 } else if (strcmp(name, "notlong") == 0) {
1288 if (out) out->screenLayout =
1289 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1290 | ResTable_config::SCREENLONG_NO;
1291 return true;
1292 }
1293
1294 return false;
1295}
1296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297bool AaptGroupEntry::getOrientationName(const char* name,
1298 ResTable_config* out)
1299{
1300 if (strcmp(name, kWildcardName) == 0) {
1301 if (out) out->orientation = out->ORIENTATION_ANY;
1302 return true;
1303 } else if (strcmp(name, "port") == 0) {
1304 if (out) out->orientation = out->ORIENTATION_PORT;
1305 return true;
1306 } else if (strcmp(name, "land") == 0) {
1307 if (out) out->orientation = out->ORIENTATION_LAND;
1308 return true;
1309 } else if (strcmp(name, "square") == 0) {
1310 if (out) out->orientation = out->ORIENTATION_SQUARE;
1311 return true;
1312 }
1313
1314 return false;
1315}
1316
Tobias Haamel27b28b32010-02-09 23:09:17 +01001317bool AaptGroupEntry::getUiModeTypeName(const char* name,
1318 ResTable_config* out)
1319{
1320 if (strcmp(name, kWildcardName) == 0) {
1321 if (out) out->uiMode =
1322 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
Dianne Hackborn7299c412010-03-04 18:41:49 -08001323 | ResTable_config::UI_MODE_TYPE_ANY;
1324 return true;
1325 } else if (strcmp(name, "desk") == 0) {
1326 if (out) out->uiMode =
1327 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1328 | ResTable_config::UI_MODE_TYPE_DESK;
Tobias Haamel27b28b32010-02-09 23:09:17 +01001329 return true;
1330 } else if (strcmp(name, "car") == 0) {
1331 if (out) out->uiMode =
1332 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1333 | ResTable_config::UI_MODE_TYPE_CAR;
1334 return true;
Dianne Hackborne360bb62011-05-20 16:11:04 -07001335 } else if (strcmp(name, "television") == 0) {
1336 if (out) out->uiMode =
1337 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1338 | ResTable_config::UI_MODE_TYPE_TELEVISION;
1339 return true;
Joe Onorato44fcb832011-12-14 20:59:30 -08001340 } else if (strcmp(name, "appliance") == 0) {
1341 if (out) out->uiMode =
1342 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1343 | ResTable_config::UI_MODE_TYPE_APPLIANCE;
1344 return true;
John Spurlock6c191292014-04-03 16:37:27 -04001345 } else if (strcmp(name, "watch") == 0) {
1346 if (out) out->uiMode =
1347 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1348 | ResTable_config::UI_MODE_TYPE_WATCH;
1349 return true;
Tobias Haamel27b28b32010-02-09 23:09:17 +01001350 }
1351
1352 return false;
1353}
1354
1355bool AaptGroupEntry::getUiModeNightName(const char* name,
1356 ResTable_config* out)
1357{
1358 if (strcmp(name, kWildcardName) == 0) {
1359 if (out) out->uiMode =
1360 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1361 | ResTable_config::UI_MODE_NIGHT_ANY;
1362 return true;
1363 } else if (strcmp(name, "night") == 0) {
1364 if (out) out->uiMode =
1365 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1366 | ResTable_config::UI_MODE_NIGHT_YES;
1367 return true;
1368 } else if (strcmp(name, "notnight") == 0) {
1369 if (out) out->uiMode =
1370 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1371 | ResTable_config::UI_MODE_NIGHT_NO;
1372 return true;
1373 }
1374
1375 return false;
1376}
1377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378bool AaptGroupEntry::getDensityName(const char* name,
1379 ResTable_config* out)
1380{
1381 if (strcmp(name, kWildcardName) == 0) {
Dianne Hackborna53b8282009-07-17 11:13:48 -07001382 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 return true;
1384 }
Dianne Hackborna53b8282009-07-17 11:13:48 -07001385
1386 if (strcmp(name, "nodpi") == 0) {
1387 if (out) out->density = ResTable_config::DENSITY_NONE;
1388 return true;
1389 }
1390
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001391 if (strcmp(name, "ldpi") == 0) {
1392 if (out) out->density = ResTable_config::DENSITY_LOW;
1393 return true;
1394 }
1395
1396 if (strcmp(name, "mdpi") == 0) {
1397 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
1398 return true;
1399 }
1400
Dianne Hackbornb96cbbd2011-05-27 13:40:26 -07001401 if (strcmp(name, "tvdpi") == 0) {
1402 if (out) out->density = ResTable_config::DENSITY_TV;
1403 return true;
1404 }
1405
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001406 if (strcmp(name, "hdpi") == 0) {
1407 if (out) out->density = ResTable_config::DENSITY_HIGH;
1408 return true;
1409 }
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001410
Dianne Hackborn588feee2010-06-04 14:36:39 -07001411 if (strcmp(name, "xhdpi") == 0) {
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001412 if (out) out->density = ResTable_config::DENSITY_XHIGH;
Dianne Hackborn588feee2010-06-04 14:36:39 -07001413 return true;
1414 }
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001415
1416 if (strcmp(name, "xxhdpi") == 0) {
1417 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
1418 return true;
1419 }
1420
Dianne Hackborn56a23012013-02-12 15:41:49 -08001421 if (strcmp(name, "xxxhdpi") == 0) {
1422 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
1423 return true;
1424 }
1425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 char* c = (char*)name;
1427 while (*c >= '0' && *c <= '9') {
1428 c++;
1429 }
1430
1431 // check that we have 'dpi' after the last digit.
1432 if (toupper(c[0]) != 'D' ||
1433 toupper(c[1]) != 'P' ||
1434 toupper(c[2]) != 'I' ||
1435 c[3] != 0) {
1436 return false;
1437 }
1438
1439 // temporarily replace the first letter with \0 to
1440 // use atoi.
1441 char tmp = c[0];
1442 c[0] = '\0';
1443
1444 int d = atoi(name);
1445 c[0] = tmp;
1446
1447 if (d != 0) {
1448 if (out) out->density = d;
1449 return true;
1450 }
1451
1452 return false;
1453}
1454
1455bool AaptGroupEntry::getTouchscreenName(const char* name,
1456 ResTable_config* out)
1457{
1458 if (strcmp(name, kWildcardName) == 0) {
1459 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
1460 return true;
1461 } else if (strcmp(name, "notouch") == 0) {
1462 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
1463 return true;
1464 } else if (strcmp(name, "stylus") == 0) {
1465 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
1466 return true;
1467 } else if (strcmp(name, "finger") == 0) {
1468 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
1469 return true;
1470 }
1471
1472 return false;
1473}
1474
1475bool AaptGroupEntry::getKeysHiddenName(const char* name,
1476 ResTable_config* out)
1477{
1478 uint8_t mask = 0;
1479 uint8_t value = 0;
1480 if (strcmp(name, kWildcardName) == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001481 mask = ResTable_config::MASK_KEYSHIDDEN;
1482 value = ResTable_config::KEYSHIDDEN_ANY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 } else if (strcmp(name, "keysexposed") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001484 mask = ResTable_config::MASK_KEYSHIDDEN;
1485 value = ResTable_config::KEYSHIDDEN_NO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 } else if (strcmp(name, "keyshidden") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001487 mask = ResTable_config::MASK_KEYSHIDDEN;
1488 value = ResTable_config::KEYSHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 } else if (strcmp(name, "keyssoft") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001490 mask = ResTable_config::MASK_KEYSHIDDEN;
1491 value = ResTable_config::KEYSHIDDEN_SOFT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 }
1493
1494 if (mask != 0) {
1495 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1496 return true;
1497 }
1498
1499 return false;
1500}
1501
1502bool AaptGroupEntry::getKeyboardName(const char* name,
1503 ResTable_config* out)
1504{
1505 if (strcmp(name, kWildcardName) == 0) {
1506 if (out) out->keyboard = out->KEYBOARD_ANY;
1507 return true;
1508 } else if (strcmp(name, "nokeys") == 0) {
1509 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
1510 return true;
1511 } else if (strcmp(name, "qwerty") == 0) {
1512 if (out) out->keyboard = out->KEYBOARD_QWERTY;
1513 return true;
1514 } else if (strcmp(name, "12key") == 0) {
1515 if (out) out->keyboard = out->KEYBOARD_12KEY;
1516 return true;
1517 }
1518
1519 return false;
1520}
1521
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001522bool AaptGroupEntry::getNavHiddenName(const char* name,
1523 ResTable_config* out)
1524{
1525 uint8_t mask = 0;
1526 uint8_t value = 0;
1527 if (strcmp(name, kWildcardName) == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001528 mask = ResTable_config::MASK_NAVHIDDEN;
1529 value = ResTable_config::NAVHIDDEN_ANY;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001530 } else if (strcmp(name, "navexposed") == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001531 mask = ResTable_config::MASK_NAVHIDDEN;
1532 value = ResTable_config::NAVHIDDEN_NO;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001533 } else if (strcmp(name, "navhidden") == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001534 mask = ResTable_config::MASK_NAVHIDDEN;
1535 value = ResTable_config::NAVHIDDEN_YES;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001536 }
1537
1538 if (mask != 0) {
1539 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1540 return true;
1541 }
1542
1543 return false;
1544}
1545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546bool AaptGroupEntry::getNavigationName(const char* name,
1547 ResTable_config* out)
1548{
1549 if (strcmp(name, kWildcardName) == 0) {
1550 if (out) out->navigation = out->NAVIGATION_ANY;
1551 return true;
1552 } else if (strcmp(name, "nonav") == 0) {
1553 if (out) out->navigation = out->NAVIGATION_NONAV;
1554 return true;
1555 } else if (strcmp(name, "dpad") == 0) {
1556 if (out) out->navigation = out->NAVIGATION_DPAD;
1557 return true;
1558 } else if (strcmp(name, "trackball") == 0) {
1559 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
1560 return true;
1561 } else if (strcmp(name, "wheel") == 0) {
1562 if (out) out->navigation = out->NAVIGATION_WHEEL;
1563 return true;
1564 }
1565
1566 return false;
1567}
1568
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001569bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570{
1571 if (strcmp(name, kWildcardName) == 0) {
1572 if (out) {
1573 out->screenWidth = out->SCREENWIDTH_ANY;
1574 out->screenHeight = out->SCREENHEIGHT_ANY;
1575 }
1576 return true;
1577 }
1578
1579 const char* x = name;
1580 while (*x >= '0' && *x <= '9') x++;
1581 if (x == name || *x != 'x') return false;
1582 String8 xName(name, x-name);
1583 x++;
1584
1585 const char* y = x;
1586 while (*y >= '0' && *y <= '9') y++;
1587 if (y == name || *y != 0) return false;
1588 String8 yName(x, y-x);
1589
1590 uint16_t w = (uint16_t)atoi(xName.string());
1591 uint16_t h = (uint16_t)atoi(yName.string());
1592 if (w < h) {
1593 return false;
1594 }
1595
1596 if (out) {
1597 out->screenWidth = w;
1598 out->screenHeight = h;
1599 }
1600
1601 return true;
1602}
1603
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001604bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
1605{
1606 if (strcmp(name, kWildcardName) == 0) {
1607 if (out) {
1608 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
1609 }
1610 return true;
1611 }
1612
1613 if (*name != 's') return false;
1614 name++;
1615 if (*name != 'w') return false;
1616 name++;
1617 const char* x = name;
1618 while (*x >= '0' && *x <= '9') x++;
1619 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1620 String8 xName(name, x-name);
1621
1622 if (out) {
1623 out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
1624 }
1625
1626 return true;
1627}
1628
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001629bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
1630{
1631 if (strcmp(name, kWildcardName) == 0) {
1632 if (out) {
1633 out->screenWidthDp = out->SCREENWIDTH_ANY;
1634 }
1635 return true;
1636 }
1637
1638 if (*name != 'w') return false;
1639 name++;
1640 const char* x = name;
1641 while (*x >= '0' && *x <= '9') x++;
1642 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1643 String8 xName(name, x-name);
1644
1645 if (out) {
1646 out->screenWidthDp = (uint16_t)atoi(xName.string());
1647 }
1648
1649 return true;
1650}
1651
1652bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
1653{
1654 if (strcmp(name, kWildcardName) == 0) {
1655 if (out) {
1656 out->screenHeightDp = out->SCREENWIDTH_ANY;
1657 }
1658 return true;
1659 }
1660
1661 if (*name != 'h') return false;
1662 name++;
1663 const char* x = name;
1664 while (*x >= '0' && *x <= '9') x++;
1665 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1666 String8 xName(name, x-name);
1667
1668 if (out) {
1669 out->screenHeightDp = (uint16_t)atoi(xName.string());
1670 }
1671
1672 return true;
1673}
1674
1675bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676{
1677 if (strcmp(name, kWildcardName) == 0) {
1678 if (out) {
1679 out->sdkVersion = out->SDKVERSION_ANY;
1680 out->minorVersion = out->MINORVERSION_ANY;
1681 }
1682 return true;
1683 }
1684
1685 if (*name != 'v') {
1686 return false;
1687 }
1688
1689 name++;
1690 const char* s = name;
1691 while (*s >= '0' && *s <= '9') s++;
1692 if (s == name || *s != 0) return false;
1693 String8 sdkName(name, s-name);
1694
1695 if (out) {
1696 out->sdkVersion = (uint16_t)atoi(sdkName.string());
1697 out->minorVersion = 0;
1698 }
1699
1700 return true;
1701}
1702
1703int AaptGroupEntry::compare(const AaptGroupEntry& o) const
1704{
1705 int v = mcc.compare(o.mcc);
1706 if (v == 0) v = mnc.compare(o.mnc);
1707 if (v == 0) v = locale.compare(o.locale);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001708 if (v == 0) v = layoutDirection.compare(o.layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 if (v == 0) v = vendor.compare(o.vendor);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001710 if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001711 if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
1712 if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001713 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
1714 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 if (v == 0) v = orientation.compare(o.orientation);
Tobias Haamel27b28b32010-02-09 23:09:17 +01001716 if (v == 0) v = uiModeType.compare(o.uiModeType);
1717 if (v == 0) v = uiModeNight.compare(o.uiModeNight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 if (v == 0) v = density.compare(o.density);
1719 if (v == 0) v = touchscreen.compare(o.touchscreen);
1720 if (v == 0) v = keysHidden.compare(o.keysHidden);
1721 if (v == 0) v = keyboard.compare(o.keyboard);
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001722 if (v == 0) v = navHidden.compare(o.navHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 if (v == 0) v = navigation.compare(o.navigation);
1724 if (v == 0) v = screenSize.compare(o.screenSize);
1725 if (v == 0) v = version.compare(o.version);
1726 return v;
1727}
1728
Narayan Kamath788fa412014-01-21 15:32:36 +00001729const ResTable_config AaptGroupEntry::toParams() const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730{
Dianne Hackborne6b68032011-10-13 16:26:02 -07001731 if (!mParamsChanged) {
1732 return mParams;
1733 }
1734
1735 mParamsChanged = false;
Narayan Kamath788fa412014-01-21 15:32:36 +00001736 ResTable_config& params = mParams;
1737 memset(&params, 0, sizeof(ResTable_config));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 getMccName(mcc.string(), &params);
1739 getMncName(mnc.string(), &params);
Narayan Kamath788fa412014-01-21 15:32:36 +00001740 locale.writeTo(&params);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001741 getLayoutDirectionName(layoutDirection.string(), &params);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001742 getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001743 getScreenWidthDpName(screenWidthDp.string(), &params);
1744 getScreenHeightDpName(screenHeightDp.string(), &params);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001745 getScreenLayoutSizeName(screenLayoutSize.string(), &params);
1746 getScreenLayoutLongName(screenLayoutLong.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 getOrientationName(orientation.string(), &params);
Tobias Haamel27b28b32010-02-09 23:09:17 +01001748 getUiModeTypeName(uiModeType.string(), &params);
1749 getUiModeNightName(uiModeNight.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 getDensityName(density.string(), &params);
1751 getTouchscreenName(touchscreen.string(), &params);
1752 getKeysHiddenName(keysHidden.string(), &params);
1753 getKeyboardName(keyboard.string(), &params);
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001754 getNavHiddenName(navHidden.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 getNavigationName(navigation.string(), &params);
1756 getScreenSizeName(screenSize.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 getVersionName(version.string(), &params);
Dianne Hackbornef05e072010-03-01 17:43:39 -08001758
1759 // Fix up version number based on specified parameters.
1760 int minSdk = 0;
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001761 if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
1762 || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001763 || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001764 minSdk = SDK_HONEYCOMB_MR2;
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001765 } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
Dianne Hackbornef05e072010-03-01 17:43:39 -08001766 != ResTable_config::UI_MODE_TYPE_ANY
1767 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
1768 != ResTable_config::UI_MODE_NIGHT_ANY) {
1769 minSdk = SDK_FROYO;
1770 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
1771 != ResTable_config::SCREENSIZE_ANY
1772 || (params.screenLayout&ResTable_config::MASK_SCREENLONG)
1773 != ResTable_config::SCREENLONG_ANY
1774 || params.density != ResTable_config::DENSITY_DEFAULT) {
1775 minSdk = SDK_DONUT;
1776 }
1777
1778 if (minSdk > params.sdkVersion) {
1779 params.sdkVersion = minSdk;
1780 }
1781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 return params;
1783}
1784
1785// =========================================================================
1786// =========================================================================
1787// =========================================================================
1788
1789void* AaptFile::editData(size_t size)
1790{
1791 if (size <= mBufferSize) {
1792 mDataSize = size;
1793 return mData;
1794 }
1795 size_t allocSize = (size*3)/2;
1796 void* buf = realloc(mData, allocSize);
1797 if (buf == NULL) {
1798 return NULL;
1799 }
1800 mData = buf;
1801 mDataSize = size;
1802 mBufferSize = allocSize;
1803 return buf;
1804}
1805
1806void* AaptFile::editData(size_t* outSize)
1807{
1808 if (outSize) {
1809 *outSize = mDataSize;
1810 }
1811 return mData;
1812}
1813
1814void* AaptFile::padData(size_t wordSize)
1815{
1816 const size_t extra = mDataSize%wordSize;
1817 if (extra == 0) {
1818 return mData;
1819 }
1820
1821 size_t initial = mDataSize;
1822 void* data = editData(initial+(wordSize-extra));
1823 if (data != NULL) {
1824 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
1825 }
1826 return data;
1827}
1828
1829status_t AaptFile::writeData(const void* data, size_t size)
1830{
1831 size_t end = mDataSize;
1832 size_t total = size + end;
1833 void* buf = editData(total);
1834 if (buf == NULL) {
1835 return UNKNOWN_ERROR;
1836 }
1837 memcpy(((char*)buf)+end, data, size);
1838 return NO_ERROR;
1839}
1840
1841void AaptFile::clearData()
1842{
1843 if (mData != NULL) free(mData);
1844 mData = NULL;
1845 mDataSize = 0;
1846 mBufferSize = 0;
1847}
1848
1849String8 AaptFile::getPrintableSource() const
1850{
1851 if (hasData()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001852 String8 name(mGroupEntry.toDirName(String8()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 name.appendPath(mPath);
1854 name.append(" #generated");
1855 return name;
1856 }
1857 return mSourceFile;
1858}
1859
1860// =========================================================================
1861// =========================================================================
1862// =========================================================================
1863
Adam Lesinski09384302014-01-22 16:07:42 -08001864status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865{
Adam Lesinski09384302014-01-22 16:07:42 -08001866 ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
1867 if (index >= 0 && overwriteDuplicate) {
1868 fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
1869 mFiles[index]->getSourceFile().string(),
1870 file->getSourceFile().string());
1871 removeFile(index);
1872 index = -1;
1873 }
1874
1875 if (index < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 file->mPath = mPath;
1877 mFiles.add(file->getGroupEntry(), file);
1878 return NO_ERROR;
1879 }
1880
Dianne Hackborne6b68032011-10-13 16:26:02 -07001881#if 0
1882 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1883 file->getSourceFile().string(),
1884 file->getGroupEntry().toDirName(String8()).string(),
1885 mLeaf.string(), mPath.string());
1886#endif
1887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1889 getPrintableSource().string());
1890 return UNKNOWN_ERROR;
1891}
1892
1893void AaptGroup::removeFile(size_t index)
1894{
1895 mFiles.removeItemsAt(index);
1896}
1897
Dianne Hackborne6b68032011-10-13 16:26:02 -07001898void AaptGroup::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899{
Dianne Hackborne6b68032011-10-13 16:26:02 -07001900 printf("%s%s\n", prefix.string(), getPath().string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 const size_t N=mFiles.size();
1902 size_t i;
1903 for (i=0; i<N; i++) {
1904 sp<AaptFile> file = mFiles.valueAt(i);
1905 const AaptGroupEntry& e = file->getGroupEntry();
1906 if (file->hasData()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001907 printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 (int)file->getSize());
1909 } else {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001910 printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
1911 file->getPrintableSource().string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 }
Dianne Hackborne6b68032011-10-13 16:26:02 -07001913 //printf("%s File Group Entry: %s\n", prefix.string(),
1914 // file->getGroupEntry().toDirName(String8()).string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 }
1916}
1917
1918String8 AaptGroup::getPrintableSource() const
1919{
1920 if (mFiles.size() > 0) {
1921 // Arbitrarily pull the first source file out of the list.
1922 return mFiles.valueAt(0)->getPrintableSource();
1923 }
1924
1925 // Should never hit this case, but to be safe...
1926 return getPath();
1927
1928}
1929
1930// =========================================================================
1931// =========================================================================
1932// =========================================================================
1933
1934status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1935{
1936 if (mFiles.indexOfKey(name) >= 0) {
1937 return ALREADY_EXISTS;
1938 }
1939 mFiles.add(name, file);
1940 return NO_ERROR;
1941}
1942
1943status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1944{
1945 if (mDirs.indexOfKey(name) >= 0) {
1946 return ALREADY_EXISTS;
1947 }
1948 mDirs.add(name, dir);
1949 return NO_ERROR;
1950}
1951
1952sp<AaptDir> AaptDir::makeDir(const String8& path)
1953{
1954 String8 name;
1955 String8 remain = path;
1956
1957 sp<AaptDir> subdir = this;
1958 while (name = remain.walkPath(&remain), remain != "") {
1959 subdir = subdir->makeDir(name);
1960 }
1961
1962 ssize_t i = subdir->mDirs.indexOfKey(name);
1963 if (i >= 0) {
1964 return subdir->mDirs.valueAt(i);
1965 }
1966 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1967 subdir->mDirs.add(name, dir);
1968 return dir;
1969}
1970
1971void AaptDir::removeFile(const String8& name)
1972{
1973 mFiles.removeItem(name);
1974}
1975
1976void AaptDir::removeDir(const String8& name)
1977{
1978 mDirs.removeItem(name);
1979}
1980
Adam Lesinski09384302014-01-22 16:07:42 -08001981status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file,
1982 const bool overwrite)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983{
1984 sp<AaptGroup> group;
1985 if (mFiles.indexOfKey(leafName) >= 0) {
1986 group = mFiles.valueFor(leafName);
1987 } else {
1988 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1989 mFiles.add(leafName, group);
1990 }
1991
Adam Lesinski09384302014-01-22 16:07:42 -08001992 return group->addFile(file, overwrite);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993}
1994
1995ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001996 const AaptGroupEntry& kind, const String8& resType,
Adam Lesinski09384302014-01-22 16:07:42 -08001997 sp<FilePathStore>& fullResPaths, const bool overwrite)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998{
1999 Vector<String8> fileNames;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 {
2001 DIR* dir = NULL;
2002
2003 dir = opendir(srcDir.string());
2004 if (dir == NULL) {
2005 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
2006 return UNKNOWN_ERROR;
2007 }
2008
2009 /*
2010 * Slurp the filenames out of the directory.
2011 */
2012 while (1) {
2013 struct dirent* entry;
2014
2015 entry = readdir(dir);
2016 if (entry == NULL)
2017 break;
2018
2019 if (isHidden(srcDir.string(), entry->d_name))
2020 continue;
2021
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002022 String8 name(entry->d_name);
2023 fileNames.add(name);
2024 // Add fully qualified path for dependency purposes
2025 // if we're collecting them
2026 if (fullResPaths != NULL) {
2027 fullResPaths->add(srcDir.appendPathCopy(name));
2028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 closedir(dir);
2031 }
2032
2033 ssize_t count = 0;
2034
2035 /*
2036 * Stash away the files and recursively descend into subdirectories.
2037 */
2038 const size_t N = fileNames.size();
2039 size_t i;
2040 for (i = 0; i < N; i++) {
2041 String8 pathName(srcDir);
2042 FileType type;
2043
2044 pathName.appendPath(fileNames[i].string());
2045 type = getFileType(pathName.string());
2046 if (type == kFileTypeDirectory) {
2047 sp<AaptDir> subdir;
2048 bool notAdded = false;
2049 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
2050 subdir = mDirs.valueFor(fileNames[i]);
2051 } else {
2052 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
2053 notAdded = true;
2054 }
2055 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
Adam Lesinski09384302014-01-22 16:07:42 -08002056 resType, fullResPaths, overwrite);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 if (res < NO_ERROR) {
2058 return res;
2059 }
2060 if (res > 0 && notAdded) {
2061 mDirs.add(fileNames[i], subdir);
2062 }
2063 count += res;
2064 } else if (type == kFileTypeRegular) {
2065 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
Adam Lesinski09384302014-01-22 16:07:42 -08002066 status_t err = addLeafFile(fileNames[i], file, overwrite);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 if (err != NO_ERROR) {
2068 return err;
2069 }
2070
2071 count++;
2072
2073 } else {
2074 if (bundle->getVerbose())
2075 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
2076 }
2077 }
2078
2079 return count;
2080}
2081
2082status_t AaptDir::validate() const
2083{
2084 const size_t NF = mFiles.size();
2085 const size_t ND = mDirs.size();
2086 size_t i;
2087 for (i = 0; i < NF; i++) {
2088 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
2089 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
2090 "Invalid filename. Unable to add.");
2091 return UNKNOWN_ERROR;
2092 }
2093
2094 size_t j;
2095 for (j = i+1; j < NF; j++) {
2096 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
2097 mFiles.valueAt(j)->getLeaf().string()) == 0) {
2098 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
2099 "File is case-insensitive equivalent to: %s",
2100 mFiles.valueAt(j)->getPrintableSource().string());
2101 return UNKNOWN_ERROR;
2102 }
2103
2104 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
2105 // (this is mostly caught by the "marked" stuff, below)
2106 }
2107
2108 for (j = 0; j < ND; j++) {
2109 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
2110 mDirs.valueAt(j)->getLeaf().string()) == 0) {
2111 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
2112 "File conflicts with dir from: %s",
2113 mDirs.valueAt(j)->getPrintableSource().string());
2114 return UNKNOWN_ERROR;
2115 }
2116 }
2117 }
2118
2119 for (i = 0; i < ND; i++) {
2120 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
2121 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
2122 "Invalid directory name, unable to add.");
2123 return UNKNOWN_ERROR;
2124 }
2125
2126 size_t j;
2127 for (j = i+1; j < ND; j++) {
2128 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
2129 mDirs.valueAt(j)->getLeaf().string()) == 0) {
2130 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
2131 "Directory is case-insensitive equivalent to: %s",
2132 mDirs.valueAt(j)->getPrintableSource().string());
2133 return UNKNOWN_ERROR;
2134 }
2135 }
2136
2137 status_t err = mDirs.valueAt(i)->validate();
2138 if (err != NO_ERROR) {
2139 return err;
2140 }
2141 }
2142
2143 return NO_ERROR;
2144}
2145
Dianne Hackborne6b68032011-10-13 16:26:02 -07002146void AaptDir::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147{
2148 const size_t ND=getDirs().size();
2149 size_t i;
2150 for (i=0; i<ND; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002151 getDirs().valueAt(i)->print(prefix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 }
2153
2154 const size_t NF=getFiles().size();
2155 for (i=0; i<NF; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002156 getFiles().valueAt(i)->print(prefix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 }
2158}
2159
2160String8 AaptDir::getPrintableSource() const
2161{
2162 if (mFiles.size() > 0) {
2163 // Arbitrarily pull the first file out of the list as the source dir.
2164 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
2165 }
2166 if (mDirs.size() > 0) {
2167 // Or arbitrarily pull the first dir out of the list as the source dir.
2168 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
2169 }
2170
2171 // Should never hit this case, but to be safe...
2172 return mPath;
2173
2174}
2175
2176// =========================================================================
2177// =========================================================================
2178// =========================================================================
2179
Dianne Hackborn1644c6d72012-02-06 15:33:21 -08002180status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
2181{
2182 status_t err = NO_ERROR;
2183 size_t N = javaSymbols->mSymbols.size();
2184 for (size_t i=0; i<N; i++) {
2185 const String8& name = javaSymbols->mSymbols.keyAt(i);
2186 const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
2187 ssize_t pos = mSymbols.indexOfKey(name);
2188 if (pos < 0) {
2189 entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
2190 err = UNKNOWN_ERROR;
2191 continue;
2192 }
2193 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
2194 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
2195 mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
2196 }
2197
2198 N = javaSymbols->mNestedSymbols.size();
2199 for (size_t i=0; i<N; i++) {
2200 const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
2201 const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
2202 ssize_t pos = mNestedSymbols.indexOfKey(name);
2203 if (pos < 0) {
2204 SourcePos pos;
2205 pos.error("Java symbol dir %s not defined\n", name.string());
2206 err = UNKNOWN_ERROR;
2207 continue;
2208 }
2209 //printf("**** applying java symbols in dir %s\n", name.string());
2210 status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
2211 if (myerr != NO_ERROR) {
2212 err = myerr;
2213 }
2214 }
2215
2216 return err;
2217}
2218
2219// =========================================================================
2220// =========================================================================
2221// =========================================================================
2222
Dianne Hackborne6b68032011-10-13 16:26:02 -07002223AaptAssets::AaptAssets()
2224 : AaptDir(String8(), String8()),
Narayan Kamath788fa412014-01-21 15:32:36 +00002225 mHavePrivateSymbols(false),
2226 mChanged(false), mHaveIncludedAssets(false),
2227 mRes(NULL)
Dianne Hackborne6b68032011-10-13 16:26:02 -07002228{
2229}
2230
2231const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
2232 if (mChanged) {
2233 }
2234 return mGroupEntries;
2235}
2236
2237status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
2238{
2239 mChanged = true;
2240 return AaptDir::addFile(name, file);
2241}
2242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243sp<AaptFile> AaptAssets::addFile(
2244 const String8& filePath, const AaptGroupEntry& entry,
2245 const String8& srcDir, sp<AaptGroup>* outGroup,
2246 const String8& resType)
2247{
2248 sp<AaptDir> dir = this;
2249 sp<AaptGroup> group;
2250 sp<AaptFile> file;
2251 String8 root, remain(filePath), partialPath;
2252 while (remain.length() > 0) {
2253 root = remain.walkPath(&remain);
2254 partialPath.appendPath(root);
2255
2256 const String8 rootStr(root);
2257
2258 if (remain.length() == 0) {
2259 ssize_t i = dir->getFiles().indexOfKey(rootStr);
2260 if (i >= 0) {
2261 group = dir->getFiles().valueAt(i);
2262 } else {
2263 group = new AaptGroup(rootStr, filePath);
2264 status_t res = dir->addFile(rootStr, group);
2265 if (res != NO_ERROR) {
2266 return NULL;
2267 }
2268 }
2269 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
2270 status_t res = group->addFile(file);
2271 if (res != NO_ERROR) {
2272 return NULL;
2273 }
2274 break;
2275
2276 } else {
2277 ssize_t i = dir->getDirs().indexOfKey(rootStr);
2278 if (i >= 0) {
2279 dir = dir->getDirs().valueAt(i);
2280 } else {
2281 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
2282 status_t res = dir->addDir(rootStr, subdir);
2283 if (res != NO_ERROR) {
2284 return NULL;
2285 }
2286 dir = subdir;
2287 }
2288 }
2289 }
2290
2291 mGroupEntries.add(entry);
2292 if (outGroup) *outGroup = group;
2293 return file;
2294}
2295
2296void AaptAssets::addResource(const String8& leafName, const String8& path,
2297 const sp<AaptFile>& file, const String8& resType)
2298{
2299 sp<AaptDir> res = AaptDir::makeDir(kResString);
2300 String8 dirname = file->getGroupEntry().toDirName(resType);
2301 sp<AaptDir> subdir = res->makeDir(dirname);
2302 sp<AaptGroup> grr = new AaptGroup(leafName, path);
2303 grr->addFile(file);
2304
2305 subdir->addFile(leafName, grr);
2306}
2307
2308
2309ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
2310{
2311 int count;
2312 int totalCount = 0;
2313 FileType type;
2314 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
2315 const size_t dirCount =resDirs.size();
2316 sp<AaptAssets> current = this;
2317
2318 const int N = bundle->getFileSpecCount();
2319
2320 /*
2321 * If a package manifest was specified, include that first.
2322 */
2323 if (bundle->getAndroidManifestFile() != NULL) {
2324 // place at root of zip.
2325 String8 srcFile(bundle->getAndroidManifestFile());
2326 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
2327 NULL, String8());
2328 totalCount++;
2329 }
2330
2331 /*
2332 * If a directory of custom assets was supplied, slurp 'em up.
2333 */
Adam Lesinski09384302014-01-22 16:07:42 -08002334 const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs();
2335 const int AN = assetDirs.size();
2336 for (int i = 0; i < AN; i++) {
2337 FileType type = getFileType(assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002338 if (type == kFileTypeNonexistent) {
Adam Lesinski09384302014-01-22 16:07:42 -08002339 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002340 return UNKNOWN_ERROR;
2341 }
2342 if (type != kFileTypeDirectory) {
Adam Lesinski09384302014-01-22 16:07:42 -08002343 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 return UNKNOWN_ERROR;
2345 }
2346
Adam Lesinski09384302014-01-22 16:07:42 -08002347 String8 assetRoot(assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002348 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
2349 AaptGroupEntry group;
2350 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
Adam Lesinski09384302014-01-22 16:07:42 -08002351 String8(), mFullAssetPaths, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002352 if (count < 0) {
2353 totalCount = count;
2354 goto bail;
2355 }
2356 if (count > 0) {
2357 mGroupEntries.add(group);
2358 }
2359 totalCount += count;
2360
Adam Lesinski09384302014-01-22 16:07:42 -08002361 if (bundle->getVerbose()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002362 printf("Found %d custom asset file%s in %s\n",
Adam Lesinski09384302014-01-22 16:07:42 -08002363 count, (count==1) ? "" : "s", assetDirs[i]);
2364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 }
2366
2367 /*
2368 * If a directory of resource-specific assets was supplied, slurp 'em up.
2369 */
2370 for (size_t i=0; i<dirCount; i++) {
2371 const char *res = resDirs[i];
2372 if (res) {
2373 type = getFileType(res);
2374 if (type == kFileTypeNonexistent) {
2375 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
2376 return UNKNOWN_ERROR;
2377 }
2378 if (type == kFileTypeDirectory) {
2379 if (i>0) {
2380 sp<AaptAssets> nextOverlay = new AaptAssets();
2381 current->setOverlay(nextOverlay);
2382 current = nextOverlay;
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002383 current->setFullResPaths(mFullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 }
2385 count = current->slurpResourceTree(bundle, String8(res));
2386
2387 if (count < 0) {
2388 totalCount = count;
2389 goto bail;
2390 }
2391 totalCount += count;
2392 }
2393 else {
2394 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
2395 return UNKNOWN_ERROR;
2396 }
2397 }
2398
2399 }
2400 /*
2401 * Now do any additional raw files.
2402 */
2403 for (int arg=0; arg<N; arg++) {
2404 const char* assetDir = bundle->getFileSpecEntry(arg);
2405
2406 FileType type = getFileType(assetDir);
2407 if (type == kFileTypeNonexistent) {
2408 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
2409 return UNKNOWN_ERROR;
2410 }
2411 if (type != kFileTypeDirectory) {
2412 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
2413 return UNKNOWN_ERROR;
2414 }
2415
2416 String8 assetRoot(assetDir);
2417
2418 if (bundle->getVerbose())
2419 printf("Processing raw dir '%s'\n", (const char*) assetDir);
2420
2421 /*
2422 * Do a recursive traversal of subdir tree. We don't make any
2423 * guarantees about ordering, so we're okay with an inorder search
2424 * using whatever order the OS happens to hand back to us.
2425 */
Josiah Gaskin03589cc2011-06-27 16:26:02 -07002426 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 if (count < 0) {
2428 /* failure; report error and remove archive */
2429 totalCount = count;
2430 goto bail;
2431 }
2432 totalCount += count;
2433
2434 if (bundle->getVerbose())
2435 printf("Found %d asset file%s in %s\n",
2436 count, (count==1) ? "" : "s", assetDir);
2437 }
2438
2439 count = validate();
2440 if (count != NO_ERROR) {
2441 totalCount = count;
2442 goto bail;
2443 }
2444
Dianne Hackborne6b68032011-10-13 16:26:02 -07002445 count = filter(bundle);
2446 if (count != NO_ERROR) {
2447 totalCount = count;
2448 goto bail;
2449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450
2451bail:
2452 return totalCount;
2453}
2454
2455ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
2456 const AaptGroupEntry& kind,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002457 const String8& resType,
2458 sp<FilePathStore>& fullResPaths)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459{
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002460 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002461 if (res > 0) {
2462 mGroupEntries.add(kind);
2463 }
2464
2465 return res;
2466}
2467
2468ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
2469{
2470 ssize_t err = 0;
2471
2472 DIR* dir = opendir(srcDir.string());
2473 if (dir == NULL) {
2474 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
2475 return UNKNOWN_ERROR;
2476 }
2477
2478 status_t count = 0;
2479
2480 /*
2481 * Run through the directory, looking for dirs that match the
2482 * expected pattern.
2483 */
2484 while (1) {
2485 struct dirent* entry = readdir(dir);
2486 if (entry == NULL) {
2487 break;
2488 }
2489
2490 if (isHidden(srcDir.string(), entry->d_name)) {
2491 continue;
2492 }
2493
2494 String8 subdirName(srcDir);
2495 subdirName.appendPath(entry->d_name);
2496
2497 AaptGroupEntry group;
2498 String8 resType;
2499 bool b = group.initFromDirName(entry->d_name, &resType);
2500 if (!b) {
2501 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
2502 entry->d_name);
2503 err = -1;
2504 continue;
2505 }
2506
Dianne Hackborne6b68032011-10-13 16:26:02 -07002507 if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
Ficus Kirkpatrick588f2282010-08-13 14:13:08 -07002508 int maxResInt = atoi(bundle->getMaxResVersion());
Dianne Hackborne6b68032011-10-13 16:26:02 -07002509 const char *verString = group.getVersionString().string();
Ficus Kirkpatrick588f2282010-08-13 14:13:08 -07002510 int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
2511 if (dirVersionInt > maxResInt) {
2512 fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
2513 continue;
2514 }
2515 }
2516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517 FileType type = getFileType(subdirName.string());
2518
2519 if (type == kFileTypeDirectory) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002520 sp<AaptDir> dir = makeDir(resType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002522 resType, mFullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 if (res < 0) {
2524 count = res;
2525 goto bail;
2526 }
2527 if (res > 0) {
2528 mGroupEntries.add(group);
2529 count += res;
2530 }
2531
Dianne Hackborne6b68032011-10-13 16:26:02 -07002532 // Only add this directory if we don't already have a resource dir
2533 // for the current type. This ensures that we only add the dir once
2534 // for all configs.
2535 sp<AaptDir> rdir = resDir(resType);
2536 if (rdir == NULL) {
2537 mResDirs.add(dir);
2538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002539 } else {
2540 if (bundle->getVerbose()) {
2541 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
2542 }
2543 }
2544 }
2545
2546bail:
2547 closedir(dir);
2548 dir = NULL;
2549
2550 if (err != 0) {
2551 return err;
2552 }
2553 return count;
2554}
2555
2556ssize_t
2557AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
2558{
2559 int count = 0;
2560 SortedVector<AaptGroupEntry> entries;
2561
2562 ZipFile* zip = new ZipFile;
2563 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
2564 if (err != NO_ERROR) {
2565 fprintf(stderr, "error opening zip file %s\n", filename);
2566 count = err;
2567 delete zip;
2568 return -1;
2569 }
2570
2571 const int N = zip->getNumEntries();
2572 for (int i=0; i<N; i++) {
2573 ZipEntry* entry = zip->getEntryByIndex(i);
2574 if (entry->getDeleted()) {
2575 continue;
2576 }
2577
2578 String8 entryName(entry->getFileName());
2579
2580 String8 dirName = entryName.getPathDir();
2581 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
2582
2583 String8 resType;
2584 AaptGroupEntry kind;
2585
2586 String8 remain;
2587 if (entryName.walkPath(&remain) == kResourceDir) {
2588 // these are the resources, pull their type out of the directory name
2589 kind.initFromDirName(remain.walkPath().string(), &resType);
2590 } else {
2591 // these are untyped and don't have an AaptGroupEntry
2592 }
2593 if (entries.indexOf(kind) < 0) {
2594 entries.add(kind);
2595 mGroupEntries.add(kind);
2596 }
2597
2598 // use the one from the zip file if they both exist.
2599 dir->removeFile(entryName.getPathLeaf());
2600
2601 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
2602 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
2603 if (err != NO_ERROR) {
2604 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
2605 count = err;
2606 goto bail;
2607 }
2608 file->setCompressionMethod(entry->getCompressionMethod());
2609
2610#if 0
2611 if (entryName == "AndroidManifest.xml") {
2612 printf("AndroidManifest.xml\n");
2613 }
2614 printf("\n\nfile: %s\n", entryName.string());
2615#endif
2616
2617 size_t len = entry->getUncompressedLen();
2618 void* data = zip->uncompress(entry);
2619 void* buf = file->editData(len);
2620 memcpy(buf, data, len);
2621
2622#if 0
2623 const int OFF = 0;
2624 const unsigned char* p = (unsigned char*)data;
2625 const unsigned char* end = p+len;
2626 p += OFF;
2627 for (int i=0; i<32 && p < end; i++) {
2628 printf("0x%03x ", i*0x10 + OFF);
2629 for (int j=0; j<0x10 && p < end; j++) {
2630 printf(" %02x", *p);
2631 p++;
2632 }
2633 printf("\n");
2634 }
2635#endif
2636
2637 free(data);
2638
2639 count++;
2640 }
2641
2642bail:
2643 delete zip;
2644 return count;
2645}
2646
Dianne Hackborne6b68032011-10-13 16:26:02 -07002647status_t AaptAssets::filter(Bundle* bundle)
2648{
2649 ResourceFilter reqFilter;
2650 status_t err = reqFilter.parse(bundle->getConfigurations());
2651 if (err != NO_ERROR) {
2652 return err;
2653 }
2654
2655 ResourceFilter prefFilter;
2656 err = prefFilter.parse(bundle->getPreferredConfigurations());
2657 if (err != NO_ERROR) {
2658 return err;
2659 }
2660
2661 if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
2662 return NO_ERROR;
2663 }
2664
Dianne Hackbornbd9d2bc2011-10-16 14:17:07 -07002665 if (bundle->getVerbose()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002666 if (!reqFilter.isEmpty()) {
2667 printf("Applying required filter: %s\n",
2668 bundle->getConfigurations());
2669 }
2670 if (!prefFilter.isEmpty()) {
2671 printf("Applying preferred filter: %s\n",
2672 bundle->getPreferredConfigurations());
2673 }
2674 }
2675
2676 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2677 const size_t ND = resdirs.size();
2678 for (size_t i=0; i<ND; i++) {
2679 const sp<AaptDir>& dir = resdirs.itemAt(i);
2680 if (dir->getLeaf() == kValuesDir) {
2681 // The "value" dir is special since a single file defines
2682 // multiple resources, so we can not do filtering on the
2683 // files themselves.
2684 continue;
2685 }
2686 if (dir->getLeaf() == kMipmapDir) {
2687 // We also skip the "mipmap" directory, since the point of this
2688 // is to include all densities without stripping. If you put
2689 // other configurations in here as well they won't be stripped
2690 // either... So don't do that. Seriously. What is wrong with you?
2691 continue;
2692 }
2693
2694 const size_t NG = dir->getFiles().size();
2695 for (size_t j=0; j<NG; j++) {
2696 sp<AaptGroup> grp = dir->getFiles().valueAt(j);
2697
2698 // First remove any configurations we know we don't need.
2699 for (size_t k=0; k<grp->getFiles().size(); k++) {
2700 sp<AaptFile> file = grp->getFiles().valueAt(k);
2701 if (k == 0 && grp->getFiles().size() == 1) {
2702 // If this is the only file left, we need to keep it.
2703 // Otherwise the resource IDs we are using will be inconsistent
2704 // with what we get when not stripping. Sucky, but at least
2705 // for now we can rely on the back-end doing another filtering
2706 // pass to take this out and leave us with this resource name
2707 // containing no entries.
2708 continue;
2709 }
2710 if (file->getPath().getPathExtension() == ".xml") {
2711 // We can't remove .xml files at this point, because when
2712 // we parse them they may add identifier resources, so
2713 // removing them can cause our resource identifiers to
2714 // become inconsistent.
2715 continue;
2716 }
2717 const ResTable_config& config(file->getGroupEntry().toParams());
2718 if (!reqFilter.match(config)) {
2719 if (bundle->getVerbose()) {
2720 printf("Pruning unneeded resource: %s\n",
2721 file->getPrintableSource().string());
2722 }
2723 grp->removeFile(k);
2724 k--;
2725 }
2726 }
2727
2728 // Quick check: no preferred filters, nothing more to do.
2729 if (prefFilter.isEmpty()) {
2730 continue;
2731 }
2732
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002733 // Get the preferred density if there is one. We do not match exactly for density.
2734 // If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
2735 // pick xhdpi.
2736 uint32_t preferredDensity = 0;
Narayan Kamath788fa412014-01-21 15:32:36 +00002737 const SortedVector<AxisValue>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002738 if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
Narayan Kamath788fa412014-01-21 15:32:36 +00002739 preferredDensity = (*preferredConfigs)[0].intValue;
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002740 }
2741
Dianne Hackborne6b68032011-10-13 16:26:02 -07002742 // Now deal with preferred configurations.
2743 for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
2744 for (size_t k=0; k<grp->getFiles().size(); k++) {
2745 sp<AaptFile> file = grp->getFiles().valueAt(k);
2746 if (k == 0 && grp->getFiles().size() == 1) {
2747 // If this is the only file left, we need to keep it.
2748 // Otherwise the resource IDs we are using will be inconsistent
2749 // with what we get when not stripping. Sucky, but at least
2750 // for now we can rely on the back-end doing another filtering
2751 // pass to take this out and leave us with this resource name
2752 // containing no entries.
2753 continue;
2754 }
2755 if (file->getPath().getPathExtension() == ".xml") {
2756 // We can't remove .xml files at this point, because when
2757 // we parse them they may add identifier resources, so
2758 // removing them can cause our resource identifiers to
2759 // become inconsistent.
2760 continue;
2761 }
2762 const ResTable_config& config(file->getGroupEntry().toParams());
2763 if (!prefFilter.match(axis, config)) {
2764 // This is a resource we would prefer not to have. Check
2765 // to see if have a similar variation that we would like
2766 // to have and, if so, we can drop it.
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002767
2768 uint32_t bestDensity = config.density;
2769
Dianne Hackborne6b68032011-10-13 16:26:02 -07002770 for (size_t m=0; m<grp->getFiles().size(); m++) {
2771 if (m == k) continue;
2772 sp<AaptFile> mfile = grp->getFiles().valueAt(m);
2773 const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
2774 if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002775 if (axis == AXIS_DENSITY && preferredDensity > 0) {
2776 // See if there is a better density resource
2777 if (mconfig.density < bestDensity &&
2778 mconfig.density > preferredDensity &&
2779 bestDensity > preferredDensity) {
2780 // This density is between our best density and
2781 // the preferred density, therefore it is better.
2782 bestDensity = mconfig.density;
2783 } else if (mconfig.density > bestDensity &&
2784 bestDensity < preferredDensity) {
2785 // This density is better than our best density and
2786 // our best density was smaller than our preferred
2787 // density, so it is better.
2788 bestDensity = mconfig.density;
2789 }
2790 } else if (prefFilter.match(axis, mconfig)) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002791 if (bundle->getVerbose()) {
2792 printf("Pruning unneeded resource: %s\n",
2793 file->getPrintableSource().string());
2794 }
2795 grp->removeFile(k);
2796 k--;
2797 break;
2798 }
2799 }
2800 }
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002801
2802 if (axis == AXIS_DENSITY && preferredDensity > 0 &&
2803 bestDensity != config.density) {
2804 if (bundle->getVerbose()) {
2805 printf("Pruning unneeded resource: %s\n",
2806 file->getPrintableSource().string());
2807 }
2808 grp->removeFile(k);
2809 k--;
2810 }
Dianne Hackborne6b68032011-10-13 16:26:02 -07002811 }
2812 }
2813 }
2814 }
2815 }
2816
2817 return NO_ERROR;
2818}
2819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
2821{
2822 sp<AaptSymbols> sym = mSymbols.valueFor(name);
2823 if (sym == NULL) {
2824 sym = new AaptSymbols();
2825 mSymbols.add(name, sym);
2826 }
2827 return sym;
2828}
2829
Dianne Hackborn1644c6d72012-02-06 15:33:21 -08002830sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
2831{
2832 sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
2833 if (sym == NULL) {
2834 sym = new AaptSymbols();
2835 mJavaSymbols.add(name, sym);
2836 }
2837 return sym;
2838}
2839
2840status_t AaptAssets::applyJavaSymbols()
2841{
2842 size_t N = mJavaSymbols.size();
2843 for (size_t i=0; i<N; i++) {
2844 const String8& name = mJavaSymbols.keyAt(i);
2845 const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
2846 ssize_t pos = mSymbols.indexOfKey(name);
2847 if (pos < 0) {
2848 SourcePos pos;
2849 pos.error("Java symbol dir %s not defined\n", name.string());
2850 return UNKNOWN_ERROR;
2851 }
2852 //printf("**** applying java symbols in dir %s\n", name.string());
2853 status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
2854 if (err != NO_ERROR) {
2855 return err;
2856 }
2857 }
2858
2859 return NO_ERROR;
2860}
2861
2862bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
2863 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2864 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2865 // sym.isJavaSymbol ? 1 : 0);
2866 if (!mHavePrivateSymbols) return true;
2867 if (sym.isPublic) return true;
2868 if (includePrivate && sym.isJavaSymbol) return true;
2869 return false;
2870}
2871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002872status_t AaptAssets::buildIncludedResources(Bundle* bundle)
2873{
2874 if (!mHaveIncludedAssets) {
2875 // Add in all includes.
2876 const Vector<const char*>& incl = bundle->getPackageIncludes();
2877 const size_t N=incl.size();
2878 for (size_t i=0; i<N; i++) {
2879 if (bundle->getVerbose())
2880 printf("Including resources from package: %s\n", incl[i]);
2881 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
2882 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
2883 incl[i]);
2884 return UNKNOWN_ERROR;
2885 }
2886 }
2887 mHaveIncludedAssets = true;
2888 }
2889
2890 return NO_ERROR;
2891}
2892
2893status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
2894{
2895 const ResTable& res = getIncludedResources();
2896 // XXX dirty!
Narayan Kamath7c4887f2014-01-27 17:32:37 +00002897 return const_cast<ResTable&>(res).add(file->getData(), file->getSize());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002898}
2899
2900const ResTable& AaptAssets::getIncludedResources() const
2901{
2902 return mIncludedAssets.getResources(false);
2903}
2904
Dianne Hackborne6b68032011-10-13 16:26:02 -07002905void AaptAssets::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002906{
Dianne Hackborne6b68032011-10-13 16:26:02 -07002907 String8 innerPrefix(prefix);
2908 innerPrefix.append(" ");
2909 String8 innerInnerPrefix(innerPrefix);
2910 innerInnerPrefix.append(" ");
2911 printf("%sConfigurations:\n", prefix.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002912 const size_t N=mGroupEntries.size();
2913 for (size_t i=0; i<N; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002914 String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
2915 printf("%s %s\n", prefix.string(),
2916 cname != "" ? cname.string() : "(default)");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 }
2918
Dianne Hackborne6b68032011-10-13 16:26:02 -07002919 printf("\n%sFiles:\n", prefix.string());
2920 AaptDir::print(innerPrefix);
2921
2922 printf("\n%sResource Dirs:\n", prefix.string());
2923 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2924 const size_t NR = resdirs.size();
2925 for (size_t i=0; i<NR; i++) {
2926 const sp<AaptDir>& d = resdirs.itemAt(i);
2927 printf("%s Type %s\n", prefix.string(), d->getLeaf().string());
2928 d->print(innerInnerPrefix);
2929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930}
2931
Dianne Hackborne6b68032011-10-13 16:26:02 -07002932sp<AaptDir> AaptAssets::resDir(const String8& name) const
Joe Onorato1553c822009-08-30 13:36:22 -07002933{
Dianne Hackborne6b68032011-10-13 16:26:02 -07002934 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2935 const size_t N = resdirs.size();
Joe Onorato1553c822009-08-30 13:36:22 -07002936 for (size_t i=0; i<N; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002937 const sp<AaptDir>& d = resdirs.itemAt(i);
Joe Onorato1553c822009-08-30 13:36:22 -07002938 if (d->getLeaf() == name) {
2939 return d;
2940 }
2941 }
2942 return NULL;
2943}
2944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945bool
2946valid_symbol_name(const String8& symbol)
2947{
2948 static char const * const KEYWORDS[] = {
2949 "abstract", "assert", "boolean", "break",
2950 "byte", "case", "catch", "char", "class", "const", "continue",
2951 "default", "do", "double", "else", "enum", "extends", "final",
2952 "finally", "float", "for", "goto", "if", "implements", "import",
2953 "instanceof", "int", "interface", "long", "native", "new", "package",
2954 "private", "protected", "public", "return", "short", "static",
2955 "strictfp", "super", "switch", "synchronized", "this", "throw",
2956 "throws", "transient", "try", "void", "volatile", "while",
2957 "true", "false", "null",
2958 NULL
2959 };
2960 const char*const* k = KEYWORDS;
2961 const char*const s = symbol.string();
2962 while (*k) {
2963 if (0 == strcmp(s, *k)) {
2964 return false;
2965 }
2966 k++;
2967 }
2968 return true;
2969}