blob: 2149190b10bec89f87418bc36a13cd2bf0bba6d2 [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
152status_t
153AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
154{
155 ResTable_config config;
156
157 // IMSI - MCC
158 if (getMccName(part.string(), &config)) {
159 *axis = AXIS_MCC;
160 *value = config.mcc;
161 return 0;
162 }
163
164 // IMSI - MNC
165 if (getMncName(part.string(), &config)) {
166 *axis = AXIS_MNC;
167 *value = config.mnc;
168 return 0;
169 }
170
171 // locale - language
172 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
173 *axis = AXIS_LANGUAGE;
174 *value = part[1] << 8 | part[0];
175 return 0;
176 }
177
178 // locale - language_REGION
179 if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
180 && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
181 *axis = AXIS_LANGUAGE;
182 *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
183 return 0;
184 }
185
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700186 // layout direction
187 if (getLayoutDirectionName(part.string(), &config)) {
188 *axis = AXIS_LAYOUTDIR;
189 *value = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
190 return 0;
191 }
192
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700193 // smallest screen dp width
194 if (getSmallestScreenWidthDpName(part.string(), &config)) {
195 *axis = AXIS_SMALLESTSCREENWIDTHDP;
196 *value = config.smallestScreenWidthDp;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700197 return 0;
198 }
199
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700200 // screen dp width
201 if (getScreenWidthDpName(part.string(), &config)) {
202 *axis = AXIS_SCREENWIDTHDP;
203 *value = config.screenWidthDp;
204 return 0;
205 }
206
207 // screen dp height
208 if (getScreenHeightDpName(part.string(), &config)) {
209 *axis = AXIS_SCREENHEIGHTDP;
210 *value = config.screenHeightDp;
211 return 0;
212 }
213
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700214 // screen layout size
215 if (getScreenLayoutSizeName(part.string(), &config)) {
216 *axis = AXIS_SCREENLAYOUTSIZE;
217 *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
218 return 0;
219 }
220
221 // screen layout long
222 if (getScreenLayoutLongName(part.string(), &config)) {
223 *axis = AXIS_SCREENLAYOUTLONG;
224 *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
225 return 0;
226 }
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 // orientation
229 if (getOrientationName(part.string(), &config)) {
230 *axis = AXIS_ORIENTATION;
231 *value = config.orientation;
232 return 0;
233 }
234
Tobias Haamel27b28b32010-02-09 23:09:17 +0100235 // ui mode type
236 if (getUiModeTypeName(part.string(), &config)) {
237 *axis = AXIS_UIMODETYPE;
238 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
239 return 0;
240 }
241
242 // ui mode night
243 if (getUiModeNightName(part.string(), &config)) {
244 *axis = AXIS_UIMODENIGHT;
245 *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
246 return 0;
247 }
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // density
250 if (getDensityName(part.string(), &config)) {
251 *axis = AXIS_DENSITY;
252 *value = config.density;
253 return 0;
254 }
255
256 // touchscreen
257 if (getTouchscreenName(part.string(), &config)) {
258 *axis = AXIS_TOUCHSCREEN;
259 *value = config.touchscreen;
260 return 0;
261 }
262
263 // keyboard hidden
264 if (getKeysHiddenName(part.string(), &config)) {
265 *axis = AXIS_KEYSHIDDEN;
266 *value = config.inputFlags;
267 return 0;
268 }
269
270 // keyboard
271 if (getKeyboardName(part.string(), &config)) {
272 *axis = AXIS_KEYBOARD;
273 *value = config.keyboard;
274 return 0;
275 }
276
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700277 // navigation hidden
278 if (getNavHiddenName(part.string(), &config)) {
279 *axis = AXIS_NAVHIDDEN;
280 *value = config.inputFlags;
281 return 0;
282 }
283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 // navigation
285 if (getNavigationName(part.string(), &config)) {
286 *axis = AXIS_NAVIGATION;
287 *value = config.navigation;
288 return 0;
289 }
290
291 // screen size
292 if (getScreenSizeName(part.string(), &config)) {
293 *axis = AXIS_SCREENSIZE;
294 *value = config.screenSize;
295 return 0;
296 }
297
298 // version
299 if (getVersionName(part.string(), &config)) {
300 *axis = AXIS_VERSION;
301 *value = config.version;
302 return 0;
303 }
304
305 return 1;
306}
307
Dianne Hackborne6b68032011-10-13 16:26:02 -0700308uint32_t
309AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
310{
311 switch (axis) {
312 case AXIS_MCC:
313 return config.mcc;
314 case AXIS_MNC:
315 return config.mnc;
316 case AXIS_LANGUAGE:
317 return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16)
318 | (((uint32_t)config.language[1]) << 8) | (config.language[0]);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700319 case AXIS_LAYOUTDIR:
320 return config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
Dianne Hackborne6b68032011-10-13 16:26:02 -0700321 case AXIS_SCREENLAYOUTSIZE:
322 return config.screenLayout&ResTable_config::MASK_SCREENSIZE;
323 case AXIS_ORIENTATION:
324 return config.orientation;
325 case AXIS_UIMODETYPE:
326 return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
327 case AXIS_UIMODENIGHT:
328 return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
329 case AXIS_DENSITY:
330 return config.density;
331 case AXIS_TOUCHSCREEN:
332 return config.touchscreen;
333 case AXIS_KEYSHIDDEN:
334 return config.inputFlags;
335 case AXIS_KEYBOARD:
336 return config.keyboard;
337 case AXIS_NAVIGATION:
338 return config.navigation;
339 case AXIS_SCREENSIZE:
340 return config.screenSize;
341 case AXIS_SMALLESTSCREENWIDTHDP:
342 return config.smallestScreenWidthDp;
343 case AXIS_SCREENWIDTHDP:
344 return config.screenWidthDp;
345 case AXIS_SCREENHEIGHTDP:
346 return config.screenHeightDp;
347 case AXIS_VERSION:
348 return config.version;
349 }
350 return 0;
351}
352
353bool
354AaptGroupEntry::configSameExcept(const ResTable_config& config,
355 const ResTable_config& otherConfig, int axis)
356{
357 for (int i=AXIS_START; i<=AXIS_END; i++) {
358 if (i == axis) {
359 continue;
360 }
361 if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
362 return false;
363 }
364 }
365 return true;
366}
367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368bool
369AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
370{
Dianne Hackborne6b68032011-10-13 16:26:02 -0700371 mParamsChanged = true;
372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 Vector<String8> parts;
374
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700375 String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700376 String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700377 String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378
379 const char *p = dir;
380 const char *q;
381 while (NULL != (q = strchr(p, '-'))) {
382 String8 val(p, q-p);
383 val.toLower();
384 parts.add(val);
385 //printf("part: %s\n", parts[parts.size()-1].string());
386 p = q+1;
387 }
388 String8 val(p);
389 val.toLower();
390 parts.add(val);
391 //printf("part: %s\n", parts[parts.size()-1].string());
392
393 const int N = parts.size();
394 int index = 0;
395 String8 part = parts[index];
396
397 // resource type
398 if (!isValidResourceType(part)) {
399 return false;
400 }
401 *resType = part;
402
403 index++;
404 if (index == N) {
405 goto success;
406 }
407 part = parts[index];
408
409 // imsi - mcc
410 if (getMccName(part.string())) {
411 mcc = part;
412
413 index++;
414 if (index == N) {
415 goto success;
416 }
417 part = parts[index];
418 } else {
419 //printf("not mcc: %s\n", part.string());
420 }
421
422 // imsi - mnc
423 if (getMncName(part.string())) {
424 mnc = part;
425
426 index++;
427 if (index == N) {
428 goto success;
429 }
430 part = parts[index];
431 } else {
432 //printf("not mcc: %s\n", part.string());
433 }
434
435 // locale - language
436 if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
437 loc = part;
438
439 index++;
440 if (index == N) {
441 goto success;
442 }
443 part = parts[index];
444 } else {
445 //printf("not language: %s\n", part.string());
446 }
447
448 // locale - region
449 if (loc.length() > 0
450 && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
451 loc += "-";
452 part.toUpper();
453 loc += part.string() + 1;
454
455 index++;
456 if (index == N) {
457 goto success;
458 }
459 part = parts[index];
460 } else {
461 //printf("not region: %s\n", part.string());
462 }
463
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700464 if (getLayoutDirectionName(part.string())) {
465 layoutDir = part;
466
467 index++;
468 if (index == N) {
469 goto success;
470 }
471 part = parts[index];
472 } else {
473 //printf("not layout direction: %s\n", part.string());
474 }
475
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700476 if (getSmallestScreenWidthDpName(part.string())) {
477 smallestwidthdp = part;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700478
479 index++;
480 if (index == N) {
481 goto success;
482 }
483 part = parts[index];
484 } else {
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700485 //printf("not smallest screen width dp: %s\n", part.string());
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700486 }
487
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700488 if (getScreenWidthDpName(part.string())) {
489 widthdp = part;
490
491 index++;
492 if (index == N) {
493 goto success;
494 }
495 part = parts[index];
496 } else {
497 //printf("not screen width dp: %s\n", part.string());
498 }
499
500 if (getScreenHeightDpName(part.string())) {
501 heightdp = part;
502
503 index++;
504 if (index == N) {
505 goto success;
506 }
507 part = parts[index];
508 } else {
509 //printf("not screen height dp: %s\n", part.string());
510 }
511
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700512 if (getScreenLayoutSizeName(part.string())) {
513 layoutsize = part;
514
515 index++;
516 if (index == N) {
517 goto success;
518 }
519 part = parts[index];
520 } else {
521 //printf("not screen layout size: %s\n", part.string());
522 }
523
524 if (getScreenLayoutLongName(part.string())) {
525 layoutlong = part;
526
527 index++;
528 if (index == N) {
529 goto success;
530 }
531 part = parts[index];
532 } else {
533 //printf("not screen layout long: %s\n", part.string());
534 }
535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 // orientation
537 if (getOrientationName(part.string())) {
538 orient = part;
539
540 index++;
541 if (index == N) {
542 goto success;
543 }
544 part = parts[index];
545 } else {
546 //printf("not orientation: %s\n", part.string());
547 }
548
Tobias Haamel27b28b32010-02-09 23:09:17 +0100549 // ui mode type
550 if (getUiModeTypeName(part.string())) {
551 uiModeType = part;
552
553 index++;
554 if (index == N) {
555 goto success;
556 }
557 part = parts[index];
558 } else {
559 //printf("not ui mode type: %s\n", part.string());
560 }
561
562 // ui mode night
563 if (getUiModeNightName(part.string())) {
564 uiModeNight = part;
565
566 index++;
567 if (index == N) {
568 goto success;
569 }
570 part = parts[index];
571 } else {
572 //printf("not ui mode night: %s\n", part.string());
573 }
574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 // density
576 if (getDensityName(part.string())) {
577 den = part;
578
579 index++;
580 if (index == N) {
581 goto success;
582 }
583 part = parts[index];
584 } else {
585 //printf("not density: %s\n", part.string());
586 }
587
588 // touchscreen
589 if (getTouchscreenName(part.string())) {
590 touch = part;
591
592 index++;
593 if (index == N) {
594 goto success;
595 }
596 part = parts[index];
597 } else {
598 //printf("not touchscreen: %s\n", part.string());
599 }
600
601 // keyboard hidden
602 if (getKeysHiddenName(part.string())) {
603 keysHidden = part;
604
605 index++;
606 if (index == N) {
607 goto success;
608 }
609 part = parts[index];
610 } else {
611 //printf("not keysHidden: %s\n", part.string());
612 }
613
614 // keyboard
615 if (getKeyboardName(part.string())) {
616 key = part;
617
618 index++;
619 if (index == N) {
620 goto success;
621 }
622 part = parts[index];
623 } else {
624 //printf("not keyboard: %s\n", part.string());
625 }
626
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700627 // navigation hidden
628 if (getNavHiddenName(part.string())) {
629 navHidden = part;
630
631 index++;
632 if (index == N) {
633 goto success;
634 }
635 part = parts[index];
636 } else {
637 //printf("not navHidden: %s\n", part.string());
638 }
639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 if (getNavigationName(part.string())) {
641 nav = part;
642
643 index++;
644 if (index == N) {
645 goto success;
646 }
647 part = parts[index];
648 } else {
649 //printf("not navigation: %s\n", part.string());
650 }
651
652 if (getScreenSizeName(part.string())) {
653 size = part;
654
655 index++;
656 if (index == N) {
657 goto success;
658 }
659 part = parts[index];
660 } else {
661 //printf("not screen size: %s\n", part.string());
662 }
663
664 if (getVersionName(part.string())) {
665 vers = part;
666
667 index++;
668 if (index == N) {
669 goto success;
670 }
671 part = parts[index];
672 } else {
673 //printf("not version: %s\n", part.string());
674 }
675
676 // if there are extra parts, it doesn't match
677 return false;
678
679success:
680 this->mcc = mcc;
681 this->mnc = mnc;
682 this->locale = loc;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700683 this->screenLayoutSize = layoutsize;
684 this->screenLayoutLong = layoutlong;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700685 this->smallestScreenWidthDp = smallestwidthdp;
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700686 this->screenWidthDp = widthdp;
687 this->screenHeightDp = heightdp;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 this->orientation = orient;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100689 this->uiModeType = uiModeType;
690 this->uiModeNight = uiModeNight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 this->density = den;
692 this->touchscreen = touch;
693 this->keysHidden = keysHidden;
694 this->keyboard = key;
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700695 this->navHidden = navHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 this->navigation = nav;
697 this->screenSize = size;
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700698 this->layoutDirection = layoutDir;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 this->version = vers;
700
701 // what is this anyway?
702 this->vendor = "";
703
704 return true;
705}
706
707String8
708AaptGroupEntry::toString() const
709{
710 String8 s = this->mcc;
711 s += ",";
712 s += this->mnc;
713 s += ",";
714 s += this->locale;
715 s += ",";
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700716 s += layoutDirection;
717 s += ",";
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700718 s += smallestScreenWidthDp;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700719 s += ",";
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700720 s += screenWidthDp;
721 s += ",";
722 s += screenHeightDp;
723 s += ",";
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700724 s += screenLayoutSize;
725 s += ",";
726 s += screenLayoutLong;
727 s += ",";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 s += this->orientation;
729 s += ",";
Tobias Haamel27b28b32010-02-09 23:09:17 +0100730 s += uiModeType;
731 s += ",";
732 s += uiModeNight;
733 s += ",";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 s += density;
735 s += ",";
736 s += touchscreen;
737 s += ",";
738 s += keysHidden;
739 s += ",";
740 s += keyboard;
741 s += ",";
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700742 s += navHidden;
743 s += ",";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 s += navigation;
745 s += ",";
746 s += screenSize;
747 s += ",";
748 s += version;
749 return s;
750}
751
752String8
753AaptGroupEntry::toDirName(const String8& resType) const
754{
755 String8 s = resType;
756 if (this->mcc != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700757 if (s.length() > 0) {
758 s += "-";
759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 s += mcc;
761 }
762 if (this->mnc != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700763 if (s.length() > 0) {
764 s += "-";
765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 s += mnc;
767 }
768 if (this->locale != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700769 if (s.length() > 0) {
770 s += "-";
771 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 s += locale;
773 }
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700774 if (this->layoutDirection != "") {
775 if (s.length() > 0) {
776 s += "-";
777 }
778 s += layoutDirection;
779 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700780 if (this->smallestScreenWidthDp != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700781 if (s.length() > 0) {
782 s += "-";
783 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700784 s += smallestScreenWidthDp;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700785 }
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700786 if (this->screenWidthDp != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700787 if (s.length() > 0) {
788 s += "-";
789 }
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700790 s += screenWidthDp;
791 }
792 if (this->screenHeightDp != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700793 if (s.length() > 0) {
794 s += "-";
795 }
Dianne Hackbornebff8f92011-05-12 18:07:47 -0700796 s += screenHeightDp;
797 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700798 if (this->screenLayoutSize != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700799 if (s.length() > 0) {
800 s += "-";
801 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700802 s += screenLayoutSize;
803 }
804 if (this->screenLayoutLong != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700805 if (s.length() > 0) {
806 s += "-";
807 }
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700808 s += screenLayoutLong;
809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 if (this->orientation != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700811 if (s.length() > 0) {
812 s += "-";
813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 s += orientation;
815 }
Tobias Haamel27b28b32010-02-09 23:09:17 +0100816 if (this->uiModeType != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700817 if (s.length() > 0) {
818 s += "-";
819 }
Tobias Haamel27b28b32010-02-09 23:09:17 +0100820 s += uiModeType;
821 }
822 if (this->uiModeNight != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700823 if (s.length() > 0) {
824 s += "-";
825 }
Tobias Haamel27b28b32010-02-09 23:09:17 +0100826 s += uiModeNight;
827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 if (this->density != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700829 if (s.length() > 0) {
830 s += "-";
831 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 s += density;
833 }
834 if (this->touchscreen != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700835 if (s.length() > 0) {
836 s += "-";
837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 s += touchscreen;
839 }
840 if (this->keysHidden != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700841 if (s.length() > 0) {
842 s += "-";
843 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 s += keysHidden;
845 }
846 if (this->keyboard != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700847 if (s.length() > 0) {
848 s += "-";
849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 s += keyboard;
851 }
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700852 if (this->navHidden != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700853 if (s.length() > 0) {
854 s += "-";
855 }
Dianne Hackborn93e462b2009-09-15 22:50:40 -0700856 s += navHidden;
857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 if (this->navigation != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700859 if (s.length() > 0) {
860 s += "-";
861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 s += navigation;
863 }
864 if (this->screenSize != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700865 if (s.length() > 0) {
866 s += "-";
867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 s += screenSize;
869 }
870 if (this->version != "") {
Dianne Hackborne6b68032011-10-13 16:26:02 -0700871 if (s.length() > 0) {
872 s += "-";
873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 s += version;
875 }
876
877 return s;
878}
879
880bool AaptGroupEntry::getMccName(const char* name,
881 ResTable_config* out)
882{
883 if (strcmp(name, kWildcardName) == 0) {
884 if (out) out->mcc = 0;
885 return true;
886 }
887 const char* c = name;
888 if (tolower(*c) != 'm') return false;
889 c++;
890 if (tolower(*c) != 'c') return false;
891 c++;
892 if (tolower(*c) != 'c') return false;
893 c++;
894
895 const char* val = c;
896
897 while (*c >= '0' && *c <= '9') {
898 c++;
899 }
900 if (*c != 0) return false;
901 if (c-val != 3) return false;
902
903 int d = atoi(val);
904 if (d != 0) {
905 if (out) out->mcc = d;
906 return true;
907 }
908
909 return false;
910}
911
912bool AaptGroupEntry::getMncName(const char* name,
913 ResTable_config* out)
914{
915 if (strcmp(name, kWildcardName) == 0) {
916 if (out) out->mcc = 0;
917 return true;
918 }
919 const char* c = name;
920 if (tolower(*c) != 'm') return false;
921 c++;
922 if (tolower(*c) != 'n') return false;
923 c++;
924 if (tolower(*c) != 'c') return false;
925 c++;
926
927 const char* val = c;
928
929 while (*c >= '0' && *c <= '9') {
930 c++;
931 }
932 if (*c != 0) return false;
933 if (c-val == 0 || c-val > 3) return false;
934
Johan Redestig5ef0b9d2010-11-09 14:13:31 +0100935 if (out) {
936 out->mnc = atoi(val);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
938
Johan Redestig5ef0b9d2010-11-09 14:13:31 +0100939 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940}
941
942/*
943 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
944 * "default")?
945 *
946 * TODO: Should insist that the first two letters are lower case, and the
947 * second two are upper.
948 */
949bool AaptGroupEntry::getLocaleName(const char* fileName,
950 ResTable_config* out)
951{
952 if (strcmp(fileName, kWildcardName) == 0
953 || strcmp(fileName, kDefaultLocale) == 0) {
954 if (out) {
955 out->language[0] = 0;
956 out->language[1] = 0;
957 out->country[0] = 0;
958 out->country[1] = 0;
959 }
960 return true;
961 }
962
963 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
964 if (out) {
965 out->language[0] = fileName[0];
966 out->language[1] = fileName[1];
967 out->country[0] = 0;
968 out->country[1] = 0;
969 }
970 return true;
971 }
972
973 if (strlen(fileName) == 5 &&
974 isalpha(fileName[0]) &&
975 isalpha(fileName[1]) &&
976 fileName[2] == '-' &&
977 isalpha(fileName[3]) &&
978 isalpha(fileName[4])) {
979 if (out) {
980 out->language[0] = fileName[0];
981 out->language[1] = fileName[1];
982 out->country[0] = fileName[3];
983 out->country[1] = fileName[4];
984 }
985 return true;
986 }
987
988 return false;
989}
990
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700991bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
992{
993 if (strcmp(name, kWildcardName) == 0) {
994 if (out) out->screenLayout =
995 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
996 | ResTable_config::LAYOUTDIR_ANY;
997 return true;
Fabrice Di Meglio8a802db2012-09-05 13:12:02 -0700998 } else if (strcmp(name, "ldltr") == 0) {
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700999 if (out) out->screenLayout =
1000 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1001 | ResTable_config::LAYOUTDIR_LTR;
1002 return true;
Fabrice Di Meglio8a802db2012-09-05 13:12:02 -07001003 } else if (strcmp(name, "ldrtl") == 0) {
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001004 if (out) out->screenLayout =
1005 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1006 | ResTable_config::LAYOUTDIR_RTL;
1007 return true;
1008 }
1009
1010 return false;
1011}
1012
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001013bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
1014 ResTable_config* out)
1015{
1016 if (strcmp(name, kWildcardName) == 0) {
1017 if (out) out->screenLayout =
1018 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1019 | ResTable_config::SCREENSIZE_ANY;
1020 return true;
1021 } else if (strcmp(name, "small") == 0) {
1022 if (out) out->screenLayout =
1023 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1024 | ResTable_config::SCREENSIZE_SMALL;
1025 return true;
1026 } else if (strcmp(name, "normal") == 0) {
1027 if (out) out->screenLayout =
1028 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1029 | ResTable_config::SCREENSIZE_NORMAL;
1030 return true;
1031 } else if (strcmp(name, "large") == 0) {
1032 if (out) out->screenLayout =
1033 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1034 | ResTable_config::SCREENSIZE_LARGE;
1035 return true;
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001036 } else if (strcmp(name, "xlarge") == 0) {
1037 if (out) out->screenLayout =
1038 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1039 | ResTable_config::SCREENSIZE_XLARGE;
1040 return true;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001041 }
1042
1043 return false;
1044}
1045
1046bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
1047 ResTable_config* out)
1048{
1049 if (strcmp(name, kWildcardName) == 0) {
1050 if (out) out->screenLayout =
1051 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1052 | ResTable_config::SCREENLONG_ANY;
1053 return true;
1054 } else if (strcmp(name, "long") == 0) {
1055 if (out) out->screenLayout =
1056 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1057 | ResTable_config::SCREENLONG_YES;
1058 return true;
1059 } else if (strcmp(name, "notlong") == 0) {
1060 if (out) out->screenLayout =
1061 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1062 | ResTable_config::SCREENLONG_NO;
1063 return true;
1064 }
1065
1066 return false;
1067}
1068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069bool AaptGroupEntry::getOrientationName(const char* name,
1070 ResTable_config* out)
1071{
1072 if (strcmp(name, kWildcardName) == 0) {
1073 if (out) out->orientation = out->ORIENTATION_ANY;
1074 return true;
1075 } else if (strcmp(name, "port") == 0) {
1076 if (out) out->orientation = out->ORIENTATION_PORT;
1077 return true;
1078 } else if (strcmp(name, "land") == 0) {
1079 if (out) out->orientation = out->ORIENTATION_LAND;
1080 return true;
1081 } else if (strcmp(name, "square") == 0) {
1082 if (out) out->orientation = out->ORIENTATION_SQUARE;
1083 return true;
1084 }
1085
1086 return false;
1087}
1088
Tobias Haamel27b28b32010-02-09 23:09:17 +01001089bool AaptGroupEntry::getUiModeTypeName(const char* name,
1090 ResTable_config* out)
1091{
1092 if (strcmp(name, kWildcardName) == 0) {
1093 if (out) out->uiMode =
1094 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
Dianne Hackborn7299c412010-03-04 18:41:49 -08001095 | ResTable_config::UI_MODE_TYPE_ANY;
1096 return true;
1097 } else if (strcmp(name, "desk") == 0) {
1098 if (out) out->uiMode =
1099 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1100 | ResTable_config::UI_MODE_TYPE_DESK;
Tobias Haamel27b28b32010-02-09 23:09:17 +01001101 return true;
1102 } else if (strcmp(name, "car") == 0) {
1103 if (out) out->uiMode =
1104 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1105 | ResTable_config::UI_MODE_TYPE_CAR;
1106 return true;
Dianne Hackborne360bb62011-05-20 16:11:04 -07001107 } else if (strcmp(name, "television") == 0) {
1108 if (out) out->uiMode =
1109 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1110 | ResTable_config::UI_MODE_TYPE_TELEVISION;
1111 return true;
Joe Onorato44fcb832011-12-14 20:59:30 -08001112 } else if (strcmp(name, "appliance") == 0) {
1113 if (out) out->uiMode =
1114 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1115 | ResTable_config::UI_MODE_TYPE_APPLIANCE;
1116 return true;
Tobias Haamel27b28b32010-02-09 23:09:17 +01001117 }
1118
1119 return false;
1120}
1121
1122bool AaptGroupEntry::getUiModeNightName(const char* name,
1123 ResTable_config* out)
1124{
1125 if (strcmp(name, kWildcardName) == 0) {
1126 if (out) out->uiMode =
1127 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1128 | ResTable_config::UI_MODE_NIGHT_ANY;
1129 return true;
1130 } else if (strcmp(name, "night") == 0) {
1131 if (out) out->uiMode =
1132 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1133 | ResTable_config::UI_MODE_NIGHT_YES;
1134 return true;
1135 } else if (strcmp(name, "notnight") == 0) {
1136 if (out) out->uiMode =
1137 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1138 | ResTable_config::UI_MODE_NIGHT_NO;
1139 return true;
1140 }
1141
1142 return false;
1143}
1144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145bool AaptGroupEntry::getDensityName(const char* name,
1146 ResTable_config* out)
1147{
1148 if (strcmp(name, kWildcardName) == 0) {
Dianne Hackborna53b8282009-07-17 11:13:48 -07001149 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 return true;
1151 }
Dianne Hackborna53b8282009-07-17 11:13:48 -07001152
1153 if (strcmp(name, "nodpi") == 0) {
1154 if (out) out->density = ResTable_config::DENSITY_NONE;
1155 return true;
1156 }
1157
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001158 if (strcmp(name, "ldpi") == 0) {
1159 if (out) out->density = ResTable_config::DENSITY_LOW;
1160 return true;
1161 }
1162
1163 if (strcmp(name, "mdpi") == 0) {
1164 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
1165 return true;
1166 }
1167
Dianne Hackbornb96cbbd2011-05-27 13:40:26 -07001168 if (strcmp(name, "tvdpi") == 0) {
1169 if (out) out->density = ResTable_config::DENSITY_TV;
1170 return true;
1171 }
1172
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001173 if (strcmp(name, "hdpi") == 0) {
1174 if (out) out->density = ResTable_config::DENSITY_HIGH;
1175 return true;
1176 }
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001177
Dianne Hackborn588feee2010-06-04 14:36:39 -07001178 if (strcmp(name, "xhdpi") == 0) {
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001179 if (out) out->density = ResTable_config::DENSITY_XHIGH;
Dianne Hackborn588feee2010-06-04 14:36:39 -07001180 return true;
1181 }
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001182
1183 if (strcmp(name, "xxhdpi") == 0) {
1184 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
1185 return true;
1186 }
1187
Dianne Hackborn56a23012013-02-12 15:41:49 -08001188 if (strcmp(name, "xxxhdpi") == 0) {
1189 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
1190 return true;
1191 }
1192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 char* c = (char*)name;
1194 while (*c >= '0' && *c <= '9') {
1195 c++;
1196 }
1197
1198 // check that we have 'dpi' after the last digit.
1199 if (toupper(c[0]) != 'D' ||
1200 toupper(c[1]) != 'P' ||
1201 toupper(c[2]) != 'I' ||
1202 c[3] != 0) {
1203 return false;
1204 }
1205
1206 // temporarily replace the first letter with \0 to
1207 // use atoi.
1208 char tmp = c[0];
1209 c[0] = '\0';
1210
1211 int d = atoi(name);
1212 c[0] = tmp;
1213
1214 if (d != 0) {
1215 if (out) out->density = d;
1216 return true;
1217 }
1218
1219 return false;
1220}
1221
1222bool AaptGroupEntry::getTouchscreenName(const char* name,
1223 ResTable_config* out)
1224{
1225 if (strcmp(name, kWildcardName) == 0) {
1226 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
1227 return true;
1228 } else if (strcmp(name, "notouch") == 0) {
1229 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
1230 return true;
1231 } else if (strcmp(name, "stylus") == 0) {
1232 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
1233 return true;
1234 } else if (strcmp(name, "finger") == 0) {
1235 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
1236 return true;
1237 }
1238
1239 return false;
1240}
1241
1242bool AaptGroupEntry::getKeysHiddenName(const char* name,
1243 ResTable_config* out)
1244{
1245 uint8_t mask = 0;
1246 uint8_t value = 0;
1247 if (strcmp(name, kWildcardName) == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001248 mask = ResTable_config::MASK_KEYSHIDDEN;
1249 value = ResTable_config::KEYSHIDDEN_ANY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 } else if (strcmp(name, "keysexposed") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001251 mask = ResTable_config::MASK_KEYSHIDDEN;
1252 value = ResTable_config::KEYSHIDDEN_NO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 } else if (strcmp(name, "keyshidden") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001254 mask = ResTable_config::MASK_KEYSHIDDEN;
1255 value = ResTable_config::KEYSHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 } else if (strcmp(name, "keyssoft") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001257 mask = ResTable_config::MASK_KEYSHIDDEN;
1258 value = ResTable_config::KEYSHIDDEN_SOFT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
1260
1261 if (mask != 0) {
1262 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1263 return true;
1264 }
1265
1266 return false;
1267}
1268
1269bool AaptGroupEntry::getKeyboardName(const char* name,
1270 ResTable_config* out)
1271{
1272 if (strcmp(name, kWildcardName) == 0) {
1273 if (out) out->keyboard = out->KEYBOARD_ANY;
1274 return true;
1275 } else if (strcmp(name, "nokeys") == 0) {
1276 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
1277 return true;
1278 } else if (strcmp(name, "qwerty") == 0) {
1279 if (out) out->keyboard = out->KEYBOARD_QWERTY;
1280 return true;
1281 } else if (strcmp(name, "12key") == 0) {
1282 if (out) out->keyboard = out->KEYBOARD_12KEY;
1283 return true;
1284 }
1285
1286 return false;
1287}
1288
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001289bool AaptGroupEntry::getNavHiddenName(const char* name,
1290 ResTable_config* out)
1291{
1292 uint8_t mask = 0;
1293 uint8_t value = 0;
1294 if (strcmp(name, kWildcardName) == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001295 mask = ResTable_config::MASK_NAVHIDDEN;
1296 value = ResTable_config::NAVHIDDEN_ANY;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001297 } else if (strcmp(name, "navexposed") == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001298 mask = ResTable_config::MASK_NAVHIDDEN;
1299 value = ResTable_config::NAVHIDDEN_NO;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001300 } else if (strcmp(name, "navhidden") == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001301 mask = ResTable_config::MASK_NAVHIDDEN;
1302 value = ResTable_config::NAVHIDDEN_YES;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001303 }
1304
1305 if (mask != 0) {
1306 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1307 return true;
1308 }
1309
1310 return false;
1311}
1312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313bool AaptGroupEntry::getNavigationName(const char* name,
1314 ResTable_config* out)
1315{
1316 if (strcmp(name, kWildcardName) == 0) {
1317 if (out) out->navigation = out->NAVIGATION_ANY;
1318 return true;
1319 } else if (strcmp(name, "nonav") == 0) {
1320 if (out) out->navigation = out->NAVIGATION_NONAV;
1321 return true;
1322 } else if (strcmp(name, "dpad") == 0) {
1323 if (out) out->navigation = out->NAVIGATION_DPAD;
1324 return true;
1325 } else if (strcmp(name, "trackball") == 0) {
1326 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
1327 return true;
1328 } else if (strcmp(name, "wheel") == 0) {
1329 if (out) out->navigation = out->NAVIGATION_WHEEL;
1330 return true;
1331 }
1332
1333 return false;
1334}
1335
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001336bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337{
1338 if (strcmp(name, kWildcardName) == 0) {
1339 if (out) {
1340 out->screenWidth = out->SCREENWIDTH_ANY;
1341 out->screenHeight = out->SCREENHEIGHT_ANY;
1342 }
1343 return true;
1344 }
1345
1346 const char* x = name;
1347 while (*x >= '0' && *x <= '9') x++;
1348 if (x == name || *x != 'x') return false;
1349 String8 xName(name, x-name);
1350 x++;
1351
1352 const char* y = x;
1353 while (*y >= '0' && *y <= '9') y++;
1354 if (y == name || *y != 0) return false;
1355 String8 yName(x, y-x);
1356
1357 uint16_t w = (uint16_t)atoi(xName.string());
1358 uint16_t h = (uint16_t)atoi(yName.string());
1359 if (w < h) {
1360 return false;
1361 }
1362
1363 if (out) {
1364 out->screenWidth = w;
1365 out->screenHeight = h;
1366 }
1367
1368 return true;
1369}
1370
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001371bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
1372{
1373 if (strcmp(name, kWildcardName) == 0) {
1374 if (out) {
1375 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
1376 }
1377 return true;
1378 }
1379
1380 if (*name != 's') return false;
1381 name++;
1382 if (*name != 'w') return false;
1383 name++;
1384 const char* x = name;
1385 while (*x >= '0' && *x <= '9') x++;
1386 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1387 String8 xName(name, x-name);
1388
1389 if (out) {
1390 out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
1391 }
1392
1393 return true;
1394}
1395
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001396bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
1397{
1398 if (strcmp(name, kWildcardName) == 0) {
1399 if (out) {
1400 out->screenWidthDp = out->SCREENWIDTH_ANY;
1401 }
1402 return true;
1403 }
1404
1405 if (*name != 'w') return false;
1406 name++;
1407 const char* x = name;
1408 while (*x >= '0' && *x <= '9') x++;
1409 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1410 String8 xName(name, x-name);
1411
1412 if (out) {
1413 out->screenWidthDp = (uint16_t)atoi(xName.string());
1414 }
1415
1416 return true;
1417}
1418
1419bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
1420{
1421 if (strcmp(name, kWildcardName) == 0) {
1422 if (out) {
1423 out->screenHeightDp = out->SCREENWIDTH_ANY;
1424 }
1425 return true;
1426 }
1427
1428 if (*name != 'h') return false;
1429 name++;
1430 const char* x = name;
1431 while (*x >= '0' && *x <= '9') x++;
1432 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1433 String8 xName(name, x-name);
1434
1435 if (out) {
1436 out->screenHeightDp = (uint16_t)atoi(xName.string());
1437 }
1438
1439 return true;
1440}
1441
1442bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443{
1444 if (strcmp(name, kWildcardName) == 0) {
1445 if (out) {
1446 out->sdkVersion = out->SDKVERSION_ANY;
1447 out->minorVersion = out->MINORVERSION_ANY;
1448 }
1449 return true;
1450 }
1451
1452 if (*name != 'v') {
1453 return false;
1454 }
1455
1456 name++;
1457 const char* s = name;
1458 while (*s >= '0' && *s <= '9') s++;
1459 if (s == name || *s != 0) return false;
1460 String8 sdkName(name, s-name);
1461
1462 if (out) {
1463 out->sdkVersion = (uint16_t)atoi(sdkName.string());
1464 out->minorVersion = 0;
1465 }
1466
1467 return true;
1468}
1469
1470int AaptGroupEntry::compare(const AaptGroupEntry& o) const
1471{
1472 int v = mcc.compare(o.mcc);
1473 if (v == 0) v = mnc.compare(o.mnc);
1474 if (v == 0) v = locale.compare(o.locale);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001475 if (v == 0) v = layoutDirection.compare(o.layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 if (v == 0) v = vendor.compare(o.vendor);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001477 if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001478 if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
1479 if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001480 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
1481 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 if (v == 0) v = orientation.compare(o.orientation);
Tobias Haamel27b28b32010-02-09 23:09:17 +01001483 if (v == 0) v = uiModeType.compare(o.uiModeType);
1484 if (v == 0) v = uiModeNight.compare(o.uiModeNight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 if (v == 0) v = density.compare(o.density);
1486 if (v == 0) v = touchscreen.compare(o.touchscreen);
1487 if (v == 0) v = keysHidden.compare(o.keysHidden);
1488 if (v == 0) v = keyboard.compare(o.keyboard);
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001489 if (v == 0) v = navHidden.compare(o.navHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 if (v == 0) v = navigation.compare(o.navigation);
1491 if (v == 0) v = screenSize.compare(o.screenSize);
1492 if (v == 0) v = version.compare(o.version);
1493 return v;
1494}
1495
Dianne Hackborne6b68032011-10-13 16:26:02 -07001496const ResTable_config& AaptGroupEntry::toParams() const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497{
Dianne Hackborne6b68032011-10-13 16:26:02 -07001498 if (!mParamsChanged) {
1499 return mParams;
1500 }
1501
1502 mParamsChanged = false;
1503 ResTable_config& params(mParams);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 memset(&params, 0, sizeof(params));
1505 getMccName(mcc.string(), &params);
1506 getMncName(mnc.string(), &params);
1507 getLocaleName(locale.string(), &params);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001508 getLayoutDirectionName(layoutDirection.string(), &params);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001509 getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001510 getScreenWidthDpName(screenWidthDp.string(), &params);
1511 getScreenHeightDpName(screenHeightDp.string(), &params);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001512 getScreenLayoutSizeName(screenLayoutSize.string(), &params);
1513 getScreenLayoutLongName(screenLayoutLong.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 getOrientationName(orientation.string(), &params);
Tobias Haamel27b28b32010-02-09 23:09:17 +01001515 getUiModeTypeName(uiModeType.string(), &params);
1516 getUiModeNightName(uiModeNight.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 getDensityName(density.string(), &params);
1518 getTouchscreenName(touchscreen.string(), &params);
1519 getKeysHiddenName(keysHidden.string(), &params);
1520 getKeyboardName(keyboard.string(), &params);
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001521 getNavHiddenName(navHidden.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 getNavigationName(navigation.string(), &params);
1523 getScreenSizeName(screenSize.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 getVersionName(version.string(), &params);
Dianne Hackbornef05e072010-03-01 17:43:39 -08001525
1526 // Fix up version number based on specified parameters.
1527 int minSdk = 0;
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001528 if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
1529 || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001530 || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001531 minSdk = SDK_HONEYCOMB_MR2;
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001532 } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
Dianne Hackbornef05e072010-03-01 17:43:39 -08001533 != ResTable_config::UI_MODE_TYPE_ANY
1534 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
1535 != ResTable_config::UI_MODE_NIGHT_ANY) {
1536 minSdk = SDK_FROYO;
1537 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
1538 != ResTable_config::SCREENSIZE_ANY
1539 || (params.screenLayout&ResTable_config::MASK_SCREENLONG)
1540 != ResTable_config::SCREENLONG_ANY
1541 || params.density != ResTable_config::DENSITY_DEFAULT) {
1542 minSdk = SDK_DONUT;
1543 }
1544
1545 if (minSdk > params.sdkVersion) {
1546 params.sdkVersion = minSdk;
1547 }
1548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 return params;
1550}
1551
1552// =========================================================================
1553// =========================================================================
1554// =========================================================================
1555
1556void* AaptFile::editData(size_t size)
1557{
1558 if (size <= mBufferSize) {
1559 mDataSize = size;
1560 return mData;
1561 }
1562 size_t allocSize = (size*3)/2;
1563 void* buf = realloc(mData, allocSize);
1564 if (buf == NULL) {
1565 return NULL;
1566 }
1567 mData = buf;
1568 mDataSize = size;
1569 mBufferSize = allocSize;
1570 return buf;
1571}
1572
1573void* AaptFile::editData(size_t* outSize)
1574{
1575 if (outSize) {
1576 *outSize = mDataSize;
1577 }
1578 return mData;
1579}
1580
1581void* AaptFile::padData(size_t wordSize)
1582{
1583 const size_t extra = mDataSize%wordSize;
1584 if (extra == 0) {
1585 return mData;
1586 }
1587
1588 size_t initial = mDataSize;
1589 void* data = editData(initial+(wordSize-extra));
1590 if (data != NULL) {
1591 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
1592 }
1593 return data;
1594}
1595
1596status_t AaptFile::writeData(const void* data, size_t size)
1597{
1598 size_t end = mDataSize;
1599 size_t total = size + end;
1600 void* buf = editData(total);
1601 if (buf == NULL) {
1602 return UNKNOWN_ERROR;
1603 }
1604 memcpy(((char*)buf)+end, data, size);
1605 return NO_ERROR;
1606}
1607
1608void AaptFile::clearData()
1609{
1610 if (mData != NULL) free(mData);
1611 mData = NULL;
1612 mDataSize = 0;
1613 mBufferSize = 0;
1614}
1615
1616String8 AaptFile::getPrintableSource() const
1617{
1618 if (hasData()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001619 String8 name(mGroupEntry.toDirName(String8()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 name.appendPath(mPath);
1621 name.append(" #generated");
1622 return name;
1623 }
1624 return mSourceFile;
1625}
1626
1627// =========================================================================
1628// =========================================================================
1629// =========================================================================
1630
1631status_t AaptGroup::addFile(const sp<AaptFile>& file)
1632{
1633 if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
1634 file->mPath = mPath;
1635 mFiles.add(file->getGroupEntry(), file);
1636 return NO_ERROR;
1637 }
1638
Dianne Hackborne6b68032011-10-13 16:26:02 -07001639#if 0
1640 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1641 file->getSourceFile().string(),
1642 file->getGroupEntry().toDirName(String8()).string(),
1643 mLeaf.string(), mPath.string());
1644#endif
1645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1647 getPrintableSource().string());
1648 return UNKNOWN_ERROR;
1649}
1650
1651void AaptGroup::removeFile(size_t index)
1652{
1653 mFiles.removeItemsAt(index);
1654}
1655
Dianne Hackborne6b68032011-10-13 16:26:02 -07001656void AaptGroup::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657{
Dianne Hackborne6b68032011-10-13 16:26:02 -07001658 printf("%s%s\n", prefix.string(), getPath().string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 const size_t N=mFiles.size();
1660 size_t i;
1661 for (i=0; i<N; i++) {
1662 sp<AaptFile> file = mFiles.valueAt(i);
1663 const AaptGroupEntry& e = file->getGroupEntry();
1664 if (file->hasData()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001665 printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 (int)file->getSize());
1667 } else {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001668 printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
1669 file->getPrintableSource().string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 }
Dianne Hackborne6b68032011-10-13 16:26:02 -07001671 //printf("%s File Group Entry: %s\n", prefix.string(),
1672 // file->getGroupEntry().toDirName(String8()).string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 }
1674}
1675
1676String8 AaptGroup::getPrintableSource() const
1677{
1678 if (mFiles.size() > 0) {
1679 // Arbitrarily pull the first source file out of the list.
1680 return mFiles.valueAt(0)->getPrintableSource();
1681 }
1682
1683 // Should never hit this case, but to be safe...
1684 return getPath();
1685
1686}
1687
1688// =========================================================================
1689// =========================================================================
1690// =========================================================================
1691
1692status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1693{
1694 if (mFiles.indexOfKey(name) >= 0) {
1695 return ALREADY_EXISTS;
1696 }
1697 mFiles.add(name, file);
1698 return NO_ERROR;
1699}
1700
1701status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1702{
1703 if (mDirs.indexOfKey(name) >= 0) {
1704 return ALREADY_EXISTS;
1705 }
1706 mDirs.add(name, dir);
1707 return NO_ERROR;
1708}
1709
1710sp<AaptDir> AaptDir::makeDir(const String8& path)
1711{
1712 String8 name;
1713 String8 remain = path;
1714
1715 sp<AaptDir> subdir = this;
1716 while (name = remain.walkPath(&remain), remain != "") {
1717 subdir = subdir->makeDir(name);
1718 }
1719
1720 ssize_t i = subdir->mDirs.indexOfKey(name);
1721 if (i >= 0) {
1722 return subdir->mDirs.valueAt(i);
1723 }
1724 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1725 subdir->mDirs.add(name, dir);
1726 return dir;
1727}
1728
1729void AaptDir::removeFile(const String8& name)
1730{
1731 mFiles.removeItem(name);
1732}
1733
1734void AaptDir::removeDir(const String8& name)
1735{
1736 mDirs.removeItem(name);
1737}
1738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
1740{
1741 sp<AaptGroup> group;
1742 if (mFiles.indexOfKey(leafName) >= 0) {
1743 group = mFiles.valueFor(leafName);
1744 } else {
1745 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1746 mFiles.add(leafName, group);
1747 }
1748
1749 return group->addFile(file);
1750}
1751
1752ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001753 const AaptGroupEntry& kind, const String8& resType,
1754 sp<FilePathStore>& fullResPaths)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755{
1756 Vector<String8> fileNames;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 {
1758 DIR* dir = NULL;
1759
1760 dir = opendir(srcDir.string());
1761 if (dir == NULL) {
1762 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1763 return UNKNOWN_ERROR;
1764 }
1765
1766 /*
1767 * Slurp the filenames out of the directory.
1768 */
1769 while (1) {
1770 struct dirent* entry;
1771
1772 entry = readdir(dir);
1773 if (entry == NULL)
1774 break;
1775
1776 if (isHidden(srcDir.string(), entry->d_name))
1777 continue;
1778
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001779 String8 name(entry->d_name);
1780 fileNames.add(name);
1781 // Add fully qualified path for dependency purposes
1782 // if we're collecting them
1783 if (fullResPaths != NULL) {
1784 fullResPaths->add(srcDir.appendPathCopy(name));
1785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 closedir(dir);
1788 }
1789
1790 ssize_t count = 0;
1791
1792 /*
1793 * Stash away the files and recursively descend into subdirectories.
1794 */
1795 const size_t N = fileNames.size();
1796 size_t i;
1797 for (i = 0; i < N; i++) {
1798 String8 pathName(srcDir);
1799 FileType type;
1800
1801 pathName.appendPath(fileNames[i].string());
1802 type = getFileType(pathName.string());
1803 if (type == kFileTypeDirectory) {
1804 sp<AaptDir> subdir;
1805 bool notAdded = false;
1806 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1807 subdir = mDirs.valueFor(fileNames[i]);
1808 } else {
1809 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1810 notAdded = true;
1811 }
1812 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001813 resType, fullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 if (res < NO_ERROR) {
1815 return res;
1816 }
1817 if (res > 0 && notAdded) {
1818 mDirs.add(fileNames[i], subdir);
1819 }
1820 count += res;
1821 } else if (type == kFileTypeRegular) {
1822 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
1823 status_t err = addLeafFile(fileNames[i], file);
1824 if (err != NO_ERROR) {
1825 return err;
1826 }
1827
1828 count++;
1829
1830 } else {
1831 if (bundle->getVerbose())
1832 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
1833 }
1834 }
1835
1836 return count;
1837}
1838
1839status_t AaptDir::validate() const
1840{
1841 const size_t NF = mFiles.size();
1842 const size_t ND = mDirs.size();
1843 size_t i;
1844 for (i = 0; i < NF; i++) {
1845 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1846 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1847 "Invalid filename. Unable to add.");
1848 return UNKNOWN_ERROR;
1849 }
1850
1851 size_t j;
1852 for (j = i+1; j < NF; j++) {
1853 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1854 mFiles.valueAt(j)->getLeaf().string()) == 0) {
1855 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1856 "File is case-insensitive equivalent to: %s",
1857 mFiles.valueAt(j)->getPrintableSource().string());
1858 return UNKNOWN_ERROR;
1859 }
1860
1861 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1862 // (this is mostly caught by the "marked" stuff, below)
1863 }
1864
1865 for (j = 0; j < ND; j++) {
1866 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1867 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1868 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1869 "File conflicts with dir from: %s",
1870 mDirs.valueAt(j)->getPrintableSource().string());
1871 return UNKNOWN_ERROR;
1872 }
1873 }
1874 }
1875
1876 for (i = 0; i < ND; i++) {
1877 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1878 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1879 "Invalid directory name, unable to add.");
1880 return UNKNOWN_ERROR;
1881 }
1882
1883 size_t j;
1884 for (j = i+1; j < ND; j++) {
1885 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1886 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1887 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1888 "Directory is case-insensitive equivalent to: %s",
1889 mDirs.valueAt(j)->getPrintableSource().string());
1890 return UNKNOWN_ERROR;
1891 }
1892 }
1893
1894 status_t err = mDirs.valueAt(i)->validate();
1895 if (err != NO_ERROR) {
1896 return err;
1897 }
1898 }
1899
1900 return NO_ERROR;
1901}
1902
Dianne Hackborne6b68032011-10-13 16:26:02 -07001903void AaptDir::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904{
1905 const size_t ND=getDirs().size();
1906 size_t i;
1907 for (i=0; i<ND; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001908 getDirs().valueAt(i)->print(prefix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 }
1910
1911 const size_t NF=getFiles().size();
1912 for (i=0; i<NF; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001913 getFiles().valueAt(i)->print(prefix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 }
1915}
1916
1917String8 AaptDir::getPrintableSource() const
1918{
1919 if (mFiles.size() > 0) {
1920 // Arbitrarily pull the first file out of the list as the source dir.
1921 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1922 }
1923 if (mDirs.size() > 0) {
1924 // Or arbitrarily pull the first dir out of the list as the source dir.
1925 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1926 }
1927
1928 // Should never hit this case, but to be safe...
1929 return mPath;
1930
1931}
1932
1933// =========================================================================
1934// =========================================================================
1935// =========================================================================
1936
Dianne Hackborn1644c6d72012-02-06 15:33:21 -08001937status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
1938{
1939 status_t err = NO_ERROR;
1940 size_t N = javaSymbols->mSymbols.size();
1941 for (size_t i=0; i<N; i++) {
1942 const String8& name = javaSymbols->mSymbols.keyAt(i);
1943 const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
1944 ssize_t pos = mSymbols.indexOfKey(name);
1945 if (pos < 0) {
1946 entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
1947 err = UNKNOWN_ERROR;
1948 continue;
1949 }
1950 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1951 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1952 mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
1953 }
1954
1955 N = javaSymbols->mNestedSymbols.size();
1956 for (size_t i=0; i<N; i++) {
1957 const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
1958 const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
1959 ssize_t pos = mNestedSymbols.indexOfKey(name);
1960 if (pos < 0) {
1961 SourcePos pos;
1962 pos.error("Java symbol dir %s not defined\n", name.string());
1963 err = UNKNOWN_ERROR;
1964 continue;
1965 }
1966 //printf("**** applying java symbols in dir %s\n", name.string());
1967 status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
1968 if (myerr != NO_ERROR) {
1969 err = myerr;
1970 }
1971 }
1972
1973 return err;
1974}
1975
1976// =========================================================================
1977// =========================================================================
1978// =========================================================================
1979
Dianne Hackborne6b68032011-10-13 16:26:02 -07001980AaptAssets::AaptAssets()
1981 : AaptDir(String8(), String8()),
1982 mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
1983{
1984}
1985
1986const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
1987 if (mChanged) {
1988 }
1989 return mGroupEntries;
1990}
1991
1992status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
1993{
1994 mChanged = true;
1995 return AaptDir::addFile(name, file);
1996}
1997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998sp<AaptFile> AaptAssets::addFile(
1999 const String8& filePath, const AaptGroupEntry& entry,
2000 const String8& srcDir, sp<AaptGroup>* outGroup,
2001 const String8& resType)
2002{
2003 sp<AaptDir> dir = this;
2004 sp<AaptGroup> group;
2005 sp<AaptFile> file;
2006 String8 root, remain(filePath), partialPath;
2007 while (remain.length() > 0) {
2008 root = remain.walkPath(&remain);
2009 partialPath.appendPath(root);
2010
2011 const String8 rootStr(root);
2012
2013 if (remain.length() == 0) {
2014 ssize_t i = dir->getFiles().indexOfKey(rootStr);
2015 if (i >= 0) {
2016 group = dir->getFiles().valueAt(i);
2017 } else {
2018 group = new AaptGroup(rootStr, filePath);
2019 status_t res = dir->addFile(rootStr, group);
2020 if (res != NO_ERROR) {
2021 return NULL;
2022 }
2023 }
2024 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
2025 status_t res = group->addFile(file);
2026 if (res != NO_ERROR) {
2027 return NULL;
2028 }
2029 break;
2030
2031 } else {
2032 ssize_t i = dir->getDirs().indexOfKey(rootStr);
2033 if (i >= 0) {
2034 dir = dir->getDirs().valueAt(i);
2035 } else {
2036 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
2037 status_t res = dir->addDir(rootStr, subdir);
2038 if (res != NO_ERROR) {
2039 return NULL;
2040 }
2041 dir = subdir;
2042 }
2043 }
2044 }
2045
2046 mGroupEntries.add(entry);
2047 if (outGroup) *outGroup = group;
2048 return file;
2049}
2050
2051void AaptAssets::addResource(const String8& leafName, const String8& path,
2052 const sp<AaptFile>& file, const String8& resType)
2053{
2054 sp<AaptDir> res = AaptDir::makeDir(kResString);
2055 String8 dirname = file->getGroupEntry().toDirName(resType);
2056 sp<AaptDir> subdir = res->makeDir(dirname);
2057 sp<AaptGroup> grr = new AaptGroup(leafName, path);
2058 grr->addFile(file);
2059
2060 subdir->addFile(leafName, grr);
2061}
2062
2063
2064ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
2065{
2066 int count;
2067 int totalCount = 0;
2068 FileType type;
2069 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
2070 const size_t dirCount =resDirs.size();
2071 sp<AaptAssets> current = this;
2072
2073 const int N = bundle->getFileSpecCount();
2074
2075 /*
2076 * If a package manifest was specified, include that first.
2077 */
2078 if (bundle->getAndroidManifestFile() != NULL) {
2079 // place at root of zip.
2080 String8 srcFile(bundle->getAndroidManifestFile());
2081 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
2082 NULL, String8());
2083 totalCount++;
2084 }
2085
2086 /*
2087 * If a directory of custom assets was supplied, slurp 'em up.
2088 */
2089 if (bundle->getAssetSourceDir()) {
2090 const char* assetDir = bundle->getAssetSourceDir();
2091
2092 FileType type = getFileType(assetDir);
2093 if (type == kFileTypeNonexistent) {
2094 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
2095 return UNKNOWN_ERROR;
2096 }
2097 if (type != kFileTypeDirectory) {
2098 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
2099 return UNKNOWN_ERROR;
2100 }
2101
2102 String8 assetRoot(assetDir);
2103 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
2104 AaptGroupEntry group;
2105 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
Josiah Gaskin03589cc2011-06-27 16:26:02 -07002106 String8(), mFullAssetPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 if (count < 0) {
2108 totalCount = count;
2109 goto bail;
2110 }
2111 if (count > 0) {
2112 mGroupEntries.add(group);
2113 }
2114 totalCount += count;
2115
2116 if (bundle->getVerbose())
2117 printf("Found %d custom asset file%s in %s\n",
2118 count, (count==1) ? "" : "s", assetDir);
2119 }
2120
2121 /*
2122 * If a directory of resource-specific assets was supplied, slurp 'em up.
2123 */
2124 for (size_t i=0; i<dirCount; i++) {
2125 const char *res = resDirs[i];
2126 if (res) {
2127 type = getFileType(res);
2128 if (type == kFileTypeNonexistent) {
2129 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
2130 return UNKNOWN_ERROR;
2131 }
2132 if (type == kFileTypeDirectory) {
2133 if (i>0) {
2134 sp<AaptAssets> nextOverlay = new AaptAssets();
2135 current->setOverlay(nextOverlay);
2136 current = nextOverlay;
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002137 current->setFullResPaths(mFullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 }
2139 count = current->slurpResourceTree(bundle, String8(res));
2140
2141 if (count < 0) {
2142 totalCount = count;
2143 goto bail;
2144 }
2145 totalCount += count;
2146 }
2147 else {
2148 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
2149 return UNKNOWN_ERROR;
2150 }
2151 }
2152
2153 }
2154 /*
2155 * Now do any additional raw files.
2156 */
2157 for (int arg=0; arg<N; arg++) {
2158 const char* assetDir = bundle->getFileSpecEntry(arg);
2159
2160 FileType type = getFileType(assetDir);
2161 if (type == kFileTypeNonexistent) {
2162 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
2163 return UNKNOWN_ERROR;
2164 }
2165 if (type != kFileTypeDirectory) {
2166 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
2167 return UNKNOWN_ERROR;
2168 }
2169
2170 String8 assetRoot(assetDir);
2171
2172 if (bundle->getVerbose())
2173 printf("Processing raw dir '%s'\n", (const char*) assetDir);
2174
2175 /*
2176 * Do a recursive traversal of subdir tree. We don't make any
2177 * guarantees about ordering, so we're okay with an inorder search
2178 * using whatever order the OS happens to hand back to us.
2179 */
Josiah Gaskin03589cc2011-06-27 16:26:02 -07002180 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 if (count < 0) {
2182 /* failure; report error and remove archive */
2183 totalCount = count;
2184 goto bail;
2185 }
2186 totalCount += count;
2187
2188 if (bundle->getVerbose())
2189 printf("Found %d asset file%s in %s\n",
2190 count, (count==1) ? "" : "s", assetDir);
2191 }
2192
2193 count = validate();
2194 if (count != NO_ERROR) {
2195 totalCount = count;
2196 goto bail;
2197 }
2198
Dianne Hackborne6b68032011-10-13 16:26:02 -07002199 count = filter(bundle);
2200 if (count != NO_ERROR) {
2201 totalCount = count;
2202 goto bail;
2203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204
2205bail:
2206 return totalCount;
2207}
2208
2209ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
2210 const AaptGroupEntry& kind,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002211 const String8& resType,
2212 sp<FilePathStore>& fullResPaths)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213{
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002214 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 if (res > 0) {
2216 mGroupEntries.add(kind);
2217 }
2218
2219 return res;
2220}
2221
2222ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
2223{
2224 ssize_t err = 0;
2225
2226 DIR* dir = opendir(srcDir.string());
2227 if (dir == NULL) {
2228 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
2229 return UNKNOWN_ERROR;
2230 }
2231
2232 status_t count = 0;
2233
2234 /*
2235 * Run through the directory, looking for dirs that match the
2236 * expected pattern.
2237 */
2238 while (1) {
2239 struct dirent* entry = readdir(dir);
2240 if (entry == NULL) {
2241 break;
2242 }
2243
2244 if (isHidden(srcDir.string(), entry->d_name)) {
2245 continue;
2246 }
2247
2248 String8 subdirName(srcDir);
2249 subdirName.appendPath(entry->d_name);
2250
2251 AaptGroupEntry group;
2252 String8 resType;
2253 bool b = group.initFromDirName(entry->d_name, &resType);
2254 if (!b) {
2255 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
2256 entry->d_name);
2257 err = -1;
2258 continue;
2259 }
2260
Dianne Hackborne6b68032011-10-13 16:26:02 -07002261 if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
Ficus Kirkpatrick588f2282010-08-13 14:13:08 -07002262 int maxResInt = atoi(bundle->getMaxResVersion());
Dianne Hackborne6b68032011-10-13 16:26:02 -07002263 const char *verString = group.getVersionString().string();
Ficus Kirkpatrick588f2282010-08-13 14:13:08 -07002264 int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
2265 if (dirVersionInt > maxResInt) {
2266 fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
2267 continue;
2268 }
2269 }
2270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 FileType type = getFileType(subdirName.string());
2272
2273 if (type == kFileTypeDirectory) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002274 sp<AaptDir> dir = makeDir(resType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002276 resType, mFullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 if (res < 0) {
2278 count = res;
2279 goto bail;
2280 }
2281 if (res > 0) {
2282 mGroupEntries.add(group);
2283 count += res;
2284 }
2285
Dianne Hackborne6b68032011-10-13 16:26:02 -07002286 // Only add this directory if we don't already have a resource dir
2287 // for the current type. This ensures that we only add the dir once
2288 // for all configs.
2289 sp<AaptDir> rdir = resDir(resType);
2290 if (rdir == NULL) {
2291 mResDirs.add(dir);
2292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002293 } else {
2294 if (bundle->getVerbose()) {
2295 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
2296 }
2297 }
2298 }
2299
2300bail:
2301 closedir(dir);
2302 dir = NULL;
2303
2304 if (err != 0) {
2305 return err;
2306 }
2307 return count;
2308}
2309
2310ssize_t
2311AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
2312{
2313 int count = 0;
2314 SortedVector<AaptGroupEntry> entries;
2315
2316 ZipFile* zip = new ZipFile;
2317 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
2318 if (err != NO_ERROR) {
2319 fprintf(stderr, "error opening zip file %s\n", filename);
2320 count = err;
2321 delete zip;
2322 return -1;
2323 }
2324
2325 const int N = zip->getNumEntries();
2326 for (int i=0; i<N; i++) {
2327 ZipEntry* entry = zip->getEntryByIndex(i);
2328 if (entry->getDeleted()) {
2329 continue;
2330 }
2331
2332 String8 entryName(entry->getFileName());
2333
2334 String8 dirName = entryName.getPathDir();
2335 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
2336
2337 String8 resType;
2338 AaptGroupEntry kind;
2339
2340 String8 remain;
2341 if (entryName.walkPath(&remain) == kResourceDir) {
2342 // these are the resources, pull their type out of the directory name
2343 kind.initFromDirName(remain.walkPath().string(), &resType);
2344 } else {
2345 // these are untyped and don't have an AaptGroupEntry
2346 }
2347 if (entries.indexOf(kind) < 0) {
2348 entries.add(kind);
2349 mGroupEntries.add(kind);
2350 }
2351
2352 // use the one from the zip file if they both exist.
2353 dir->removeFile(entryName.getPathLeaf());
2354
2355 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
2356 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
2357 if (err != NO_ERROR) {
2358 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
2359 count = err;
2360 goto bail;
2361 }
2362 file->setCompressionMethod(entry->getCompressionMethod());
2363
2364#if 0
2365 if (entryName == "AndroidManifest.xml") {
2366 printf("AndroidManifest.xml\n");
2367 }
2368 printf("\n\nfile: %s\n", entryName.string());
2369#endif
2370
2371 size_t len = entry->getUncompressedLen();
2372 void* data = zip->uncompress(entry);
2373 void* buf = file->editData(len);
2374 memcpy(buf, data, len);
2375
2376#if 0
2377 const int OFF = 0;
2378 const unsigned char* p = (unsigned char*)data;
2379 const unsigned char* end = p+len;
2380 p += OFF;
2381 for (int i=0; i<32 && p < end; i++) {
2382 printf("0x%03x ", i*0x10 + OFF);
2383 for (int j=0; j<0x10 && p < end; j++) {
2384 printf(" %02x", *p);
2385 p++;
2386 }
2387 printf("\n");
2388 }
2389#endif
2390
2391 free(data);
2392
2393 count++;
2394 }
2395
2396bail:
2397 delete zip;
2398 return count;
2399}
2400
Dianne Hackborne6b68032011-10-13 16:26:02 -07002401status_t AaptAssets::filter(Bundle* bundle)
2402{
2403 ResourceFilter reqFilter;
2404 status_t err = reqFilter.parse(bundle->getConfigurations());
2405 if (err != NO_ERROR) {
2406 return err;
2407 }
2408
2409 ResourceFilter prefFilter;
2410 err = prefFilter.parse(bundle->getPreferredConfigurations());
2411 if (err != NO_ERROR) {
2412 return err;
2413 }
2414
2415 if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
2416 return NO_ERROR;
2417 }
2418
Dianne Hackbornbd9d2bc2011-10-16 14:17:07 -07002419 if (bundle->getVerbose()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002420 if (!reqFilter.isEmpty()) {
2421 printf("Applying required filter: %s\n",
2422 bundle->getConfigurations());
2423 }
2424 if (!prefFilter.isEmpty()) {
2425 printf("Applying preferred filter: %s\n",
2426 bundle->getPreferredConfigurations());
2427 }
2428 }
2429
2430 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2431 const size_t ND = resdirs.size();
2432 for (size_t i=0; i<ND; i++) {
2433 const sp<AaptDir>& dir = resdirs.itemAt(i);
2434 if (dir->getLeaf() == kValuesDir) {
2435 // The "value" dir is special since a single file defines
2436 // multiple resources, so we can not do filtering on the
2437 // files themselves.
2438 continue;
2439 }
2440 if (dir->getLeaf() == kMipmapDir) {
2441 // We also skip the "mipmap" directory, since the point of this
2442 // is to include all densities without stripping. If you put
2443 // other configurations in here as well they won't be stripped
2444 // either... So don't do that. Seriously. What is wrong with you?
2445 continue;
2446 }
2447
2448 const size_t NG = dir->getFiles().size();
2449 for (size_t j=0; j<NG; j++) {
2450 sp<AaptGroup> grp = dir->getFiles().valueAt(j);
2451
2452 // First remove any configurations we know we don't need.
2453 for (size_t k=0; k<grp->getFiles().size(); k++) {
2454 sp<AaptFile> file = grp->getFiles().valueAt(k);
2455 if (k == 0 && grp->getFiles().size() == 1) {
2456 // If this is the only file left, we need to keep it.
2457 // Otherwise the resource IDs we are using will be inconsistent
2458 // with what we get when not stripping. Sucky, but at least
2459 // for now we can rely on the back-end doing another filtering
2460 // pass to take this out and leave us with this resource name
2461 // containing no entries.
2462 continue;
2463 }
2464 if (file->getPath().getPathExtension() == ".xml") {
2465 // We can't remove .xml files at this point, because when
2466 // we parse them they may add identifier resources, so
2467 // removing them can cause our resource identifiers to
2468 // become inconsistent.
2469 continue;
2470 }
2471 const ResTable_config& config(file->getGroupEntry().toParams());
2472 if (!reqFilter.match(config)) {
2473 if (bundle->getVerbose()) {
2474 printf("Pruning unneeded resource: %s\n",
2475 file->getPrintableSource().string());
2476 }
2477 grp->removeFile(k);
2478 k--;
2479 }
2480 }
2481
2482 // Quick check: no preferred filters, nothing more to do.
2483 if (prefFilter.isEmpty()) {
2484 continue;
2485 }
2486
2487 // Now deal with preferred configurations.
2488 for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
2489 for (size_t k=0; k<grp->getFiles().size(); k++) {
2490 sp<AaptFile> file = grp->getFiles().valueAt(k);
2491 if (k == 0 && grp->getFiles().size() == 1) {
2492 // If this is the only file left, we need to keep it.
2493 // Otherwise the resource IDs we are using will be inconsistent
2494 // with what we get when not stripping. Sucky, but at least
2495 // for now we can rely on the back-end doing another filtering
2496 // pass to take this out and leave us with this resource name
2497 // containing no entries.
2498 continue;
2499 }
2500 if (file->getPath().getPathExtension() == ".xml") {
2501 // We can't remove .xml files at this point, because when
2502 // we parse them they may add identifier resources, so
2503 // removing them can cause our resource identifiers to
2504 // become inconsistent.
2505 continue;
2506 }
2507 const ResTable_config& config(file->getGroupEntry().toParams());
2508 if (!prefFilter.match(axis, config)) {
2509 // This is a resource we would prefer not to have. Check
2510 // to see if have a similar variation that we would like
2511 // to have and, if so, we can drop it.
2512 for (size_t m=0; m<grp->getFiles().size(); m++) {
2513 if (m == k) continue;
2514 sp<AaptFile> mfile = grp->getFiles().valueAt(m);
2515 const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
2516 if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
2517 if (prefFilter.match(axis, mconfig)) {
2518 if (bundle->getVerbose()) {
2519 printf("Pruning unneeded resource: %s\n",
2520 file->getPrintableSource().string());
2521 }
2522 grp->removeFile(k);
2523 k--;
2524 break;
2525 }
2526 }
2527 }
2528 }
2529 }
2530 }
2531 }
2532 }
2533
2534 return NO_ERROR;
2535}
2536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002537sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
2538{
2539 sp<AaptSymbols> sym = mSymbols.valueFor(name);
2540 if (sym == NULL) {
2541 sym = new AaptSymbols();
2542 mSymbols.add(name, sym);
2543 }
2544 return sym;
2545}
2546
Dianne Hackborn1644c6d72012-02-06 15:33:21 -08002547sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
2548{
2549 sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
2550 if (sym == NULL) {
2551 sym = new AaptSymbols();
2552 mJavaSymbols.add(name, sym);
2553 }
2554 return sym;
2555}
2556
2557status_t AaptAssets::applyJavaSymbols()
2558{
2559 size_t N = mJavaSymbols.size();
2560 for (size_t i=0; i<N; i++) {
2561 const String8& name = mJavaSymbols.keyAt(i);
2562 const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
2563 ssize_t pos = mSymbols.indexOfKey(name);
2564 if (pos < 0) {
2565 SourcePos pos;
2566 pos.error("Java symbol dir %s not defined\n", name.string());
2567 return UNKNOWN_ERROR;
2568 }
2569 //printf("**** applying java symbols in dir %s\n", name.string());
2570 status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
2571 if (err != NO_ERROR) {
2572 return err;
2573 }
2574 }
2575
2576 return NO_ERROR;
2577}
2578
2579bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
2580 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2581 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2582 // sym.isJavaSymbol ? 1 : 0);
2583 if (!mHavePrivateSymbols) return true;
2584 if (sym.isPublic) return true;
2585 if (includePrivate && sym.isJavaSymbol) return true;
2586 return false;
2587}
2588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589status_t AaptAssets::buildIncludedResources(Bundle* bundle)
2590{
2591 if (!mHaveIncludedAssets) {
2592 // Add in all includes.
2593 const Vector<const char*>& incl = bundle->getPackageIncludes();
2594 const size_t N=incl.size();
2595 for (size_t i=0; i<N; i++) {
2596 if (bundle->getVerbose())
2597 printf("Including resources from package: %s\n", incl[i]);
2598 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
2599 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
2600 incl[i]);
2601 return UNKNOWN_ERROR;
2602 }
2603 }
2604 mHaveIncludedAssets = true;
2605 }
2606
2607 return NO_ERROR;
2608}
2609
2610status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
2611{
2612 const ResTable& res = getIncludedResources();
2613 // XXX dirty!
2614 return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
2615}
2616
2617const ResTable& AaptAssets::getIncludedResources() const
2618{
2619 return mIncludedAssets.getResources(false);
2620}
2621
Dianne Hackborne6b68032011-10-13 16:26:02 -07002622void AaptAssets::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623{
Dianne Hackborne6b68032011-10-13 16:26:02 -07002624 String8 innerPrefix(prefix);
2625 innerPrefix.append(" ");
2626 String8 innerInnerPrefix(innerPrefix);
2627 innerInnerPrefix.append(" ");
2628 printf("%sConfigurations:\n", prefix.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 const size_t N=mGroupEntries.size();
2630 for (size_t i=0; i<N; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002631 String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
2632 printf("%s %s\n", prefix.string(),
2633 cname != "" ? cname.string() : "(default)");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002634 }
2635
Dianne Hackborne6b68032011-10-13 16:26:02 -07002636 printf("\n%sFiles:\n", prefix.string());
2637 AaptDir::print(innerPrefix);
2638
2639 printf("\n%sResource Dirs:\n", prefix.string());
2640 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2641 const size_t NR = resdirs.size();
2642 for (size_t i=0; i<NR; i++) {
2643 const sp<AaptDir>& d = resdirs.itemAt(i);
2644 printf("%s Type %s\n", prefix.string(), d->getLeaf().string());
2645 d->print(innerInnerPrefix);
2646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647}
2648
Dianne Hackborne6b68032011-10-13 16:26:02 -07002649sp<AaptDir> AaptAssets::resDir(const String8& name) const
Joe Onorato1553c822009-08-30 13:36:22 -07002650{
Dianne Hackborne6b68032011-10-13 16:26:02 -07002651 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2652 const size_t N = resdirs.size();
Joe Onorato1553c822009-08-30 13:36:22 -07002653 for (size_t i=0; i<N; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002654 const sp<AaptDir>& d = resdirs.itemAt(i);
Joe Onorato1553c822009-08-30 13:36:22 -07002655 if (d->getLeaf() == name) {
2656 return d;
2657 }
2658 }
2659 return NULL;
2660}
2661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662bool
2663valid_symbol_name(const String8& symbol)
2664{
2665 static char const * const KEYWORDS[] = {
2666 "abstract", "assert", "boolean", "break",
2667 "byte", "case", "catch", "char", "class", "const", "continue",
2668 "default", "do", "double", "else", "enum", "extends", "final",
2669 "finally", "float", "for", "goto", "if", "implements", "import",
2670 "instanceof", "int", "interface", "long", "native", "new", "package",
2671 "private", "protected", "public", "return", "short", "static",
2672 "strictfp", "super", "switch", "synchronized", "this", "throw",
2673 "throws", "transient", "try", "void", "volatile", "while",
2674 "true", "false", "null",
2675 NULL
2676 };
2677 const char*const* k = KEYWORDS;
2678 const char*const s = symbol.string();
2679 while (*k) {
2680 if (0 == strcmp(s, *k)) {
2681 return false;
2682 }
2683 k++;
2684 }
2685 return true;
2686}