blob: 8133d26aee353f5a1dba505bd8e77d8f52873357 [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);
Mattias Petersson1d766b52011-10-07 09:33:52 +0200937 if (out->mnc == 0) {
938 out->mnc = ACONFIGURATION_MNC_ZERO;
939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 }
941
Johan Redestig5ef0b9d2010-11-09 14:13:31 +0100942 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943}
944
945/*
946 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
947 * "default")?
948 *
949 * TODO: Should insist that the first two letters are lower case, and the
950 * second two are upper.
951 */
952bool AaptGroupEntry::getLocaleName(const char* fileName,
953 ResTable_config* out)
954{
955 if (strcmp(fileName, kWildcardName) == 0
956 || strcmp(fileName, kDefaultLocale) == 0) {
957 if (out) {
958 out->language[0] = 0;
959 out->language[1] = 0;
960 out->country[0] = 0;
961 out->country[1] = 0;
962 }
963 return true;
964 }
965
966 if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
967 if (out) {
968 out->language[0] = fileName[0];
969 out->language[1] = fileName[1];
970 out->country[0] = 0;
971 out->country[1] = 0;
972 }
973 return true;
974 }
975
976 if (strlen(fileName) == 5 &&
977 isalpha(fileName[0]) &&
978 isalpha(fileName[1]) &&
979 fileName[2] == '-' &&
980 isalpha(fileName[3]) &&
981 isalpha(fileName[4])) {
982 if (out) {
983 out->language[0] = fileName[0];
984 out->language[1] = fileName[1];
985 out->country[0] = fileName[3];
986 out->country[1] = fileName[4];
987 }
988 return true;
989 }
990
991 return false;
992}
993
Fabrice Di Meglio5f797992012-06-15 20:16:41 -0700994bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
995{
996 if (strcmp(name, kWildcardName) == 0) {
997 if (out) out->screenLayout =
998 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
999 | ResTable_config::LAYOUTDIR_ANY;
1000 return true;
Fabrice Di Meglio8a802db2012-09-05 13:12:02 -07001001 } else if (strcmp(name, "ldltr") == 0) {
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001002 if (out) out->screenLayout =
1003 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1004 | ResTable_config::LAYOUTDIR_LTR;
1005 return true;
Fabrice Di Meglio8a802db2012-09-05 13:12:02 -07001006 } else if (strcmp(name, "ldrtl") == 0) {
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001007 if (out) out->screenLayout =
1008 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
1009 | ResTable_config::LAYOUTDIR_RTL;
1010 return true;
1011 }
1012
1013 return false;
1014}
1015
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001016bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
1017 ResTable_config* out)
1018{
1019 if (strcmp(name, kWildcardName) == 0) {
1020 if (out) out->screenLayout =
1021 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1022 | ResTable_config::SCREENSIZE_ANY;
1023 return true;
1024 } else if (strcmp(name, "small") == 0) {
1025 if (out) out->screenLayout =
1026 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1027 | ResTable_config::SCREENSIZE_SMALL;
1028 return true;
1029 } else if (strcmp(name, "normal") == 0) {
1030 if (out) out->screenLayout =
1031 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1032 | ResTable_config::SCREENSIZE_NORMAL;
1033 return true;
1034 } else if (strcmp(name, "large") == 0) {
1035 if (out) out->screenLayout =
1036 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1037 | ResTable_config::SCREENSIZE_LARGE;
1038 return true;
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001039 } else if (strcmp(name, "xlarge") == 0) {
1040 if (out) out->screenLayout =
1041 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
1042 | ResTable_config::SCREENSIZE_XLARGE;
1043 return true;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001044 }
1045
1046 return false;
1047}
1048
1049bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
1050 ResTable_config* out)
1051{
1052 if (strcmp(name, kWildcardName) == 0) {
1053 if (out) out->screenLayout =
1054 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1055 | ResTable_config::SCREENLONG_ANY;
1056 return true;
1057 } else if (strcmp(name, "long") == 0) {
1058 if (out) out->screenLayout =
1059 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1060 | ResTable_config::SCREENLONG_YES;
1061 return true;
1062 } else if (strcmp(name, "notlong") == 0) {
1063 if (out) out->screenLayout =
1064 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
1065 | ResTable_config::SCREENLONG_NO;
1066 return true;
1067 }
1068
1069 return false;
1070}
1071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072bool AaptGroupEntry::getOrientationName(const char* name,
1073 ResTable_config* out)
1074{
1075 if (strcmp(name, kWildcardName) == 0) {
1076 if (out) out->orientation = out->ORIENTATION_ANY;
1077 return true;
1078 } else if (strcmp(name, "port") == 0) {
1079 if (out) out->orientation = out->ORIENTATION_PORT;
1080 return true;
1081 } else if (strcmp(name, "land") == 0) {
1082 if (out) out->orientation = out->ORIENTATION_LAND;
1083 return true;
1084 } else if (strcmp(name, "square") == 0) {
1085 if (out) out->orientation = out->ORIENTATION_SQUARE;
1086 return true;
1087 }
1088
1089 return false;
1090}
1091
Tobias Haamel27b28b32010-02-09 23:09:17 +01001092bool AaptGroupEntry::getUiModeTypeName(const char* name,
1093 ResTable_config* out)
1094{
1095 if (strcmp(name, kWildcardName) == 0) {
1096 if (out) out->uiMode =
1097 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
Dianne Hackborn7299c412010-03-04 18:41:49 -08001098 | ResTable_config::UI_MODE_TYPE_ANY;
1099 return true;
1100 } else if (strcmp(name, "desk") == 0) {
1101 if (out) out->uiMode =
1102 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1103 | ResTable_config::UI_MODE_TYPE_DESK;
Tobias Haamel27b28b32010-02-09 23:09:17 +01001104 return true;
1105 } else if (strcmp(name, "car") == 0) {
1106 if (out) out->uiMode =
1107 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1108 | ResTable_config::UI_MODE_TYPE_CAR;
1109 return true;
Dianne Hackborne360bb62011-05-20 16:11:04 -07001110 } else if (strcmp(name, "television") == 0) {
1111 if (out) out->uiMode =
1112 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1113 | ResTable_config::UI_MODE_TYPE_TELEVISION;
1114 return true;
Joe Onorato44fcb832011-12-14 20:59:30 -08001115 } else if (strcmp(name, "appliance") == 0) {
1116 if (out) out->uiMode =
1117 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
1118 | ResTable_config::UI_MODE_TYPE_APPLIANCE;
1119 return true;
Tobias Haamel27b28b32010-02-09 23:09:17 +01001120 }
1121
1122 return false;
1123}
1124
1125bool AaptGroupEntry::getUiModeNightName(const char* name,
1126 ResTable_config* out)
1127{
1128 if (strcmp(name, kWildcardName) == 0) {
1129 if (out) out->uiMode =
1130 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1131 | ResTable_config::UI_MODE_NIGHT_ANY;
1132 return true;
1133 } else if (strcmp(name, "night") == 0) {
1134 if (out) out->uiMode =
1135 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1136 | ResTable_config::UI_MODE_NIGHT_YES;
1137 return true;
1138 } else if (strcmp(name, "notnight") == 0) {
1139 if (out) out->uiMode =
1140 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
1141 | ResTable_config::UI_MODE_NIGHT_NO;
1142 return true;
1143 }
1144
1145 return false;
1146}
1147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148bool AaptGroupEntry::getDensityName(const char* name,
1149 ResTable_config* out)
1150{
1151 if (strcmp(name, kWildcardName) == 0) {
Dianne Hackborna53b8282009-07-17 11:13:48 -07001152 if (out) out->density = ResTable_config::DENSITY_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 return true;
1154 }
Dianne Hackborna53b8282009-07-17 11:13:48 -07001155
1156 if (strcmp(name, "nodpi") == 0) {
1157 if (out) out->density = ResTable_config::DENSITY_NONE;
1158 return true;
1159 }
1160
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001161 if (strcmp(name, "ldpi") == 0) {
1162 if (out) out->density = ResTable_config::DENSITY_LOW;
1163 return true;
1164 }
1165
1166 if (strcmp(name, "mdpi") == 0) {
1167 if (out) out->density = ResTable_config::DENSITY_MEDIUM;
1168 return true;
1169 }
1170
Dianne Hackbornb96cbbd2011-05-27 13:40:26 -07001171 if (strcmp(name, "tvdpi") == 0) {
1172 if (out) out->density = ResTable_config::DENSITY_TV;
1173 return true;
1174 }
1175
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001176 if (strcmp(name, "hdpi") == 0) {
1177 if (out) out->density = ResTable_config::DENSITY_HIGH;
1178 return true;
1179 }
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001180
Dianne Hackborn588feee2010-06-04 14:36:39 -07001181 if (strcmp(name, "xhdpi") == 0) {
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001182 if (out) out->density = ResTable_config::DENSITY_XHIGH;
Dianne Hackborn588feee2010-06-04 14:36:39 -07001183 return true;
1184 }
Dianne Hackbornd96e3df2012-01-25 15:12:23 -08001185
1186 if (strcmp(name, "xxhdpi") == 0) {
1187 if (out) out->density = ResTable_config::DENSITY_XXHIGH;
1188 return true;
1189 }
1190
Dianne Hackborn56a23012013-02-12 15:41:49 -08001191 if (strcmp(name, "xxxhdpi") == 0) {
1192 if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
1193 return true;
1194 }
1195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 char* c = (char*)name;
1197 while (*c >= '0' && *c <= '9') {
1198 c++;
1199 }
1200
1201 // check that we have 'dpi' after the last digit.
1202 if (toupper(c[0]) != 'D' ||
1203 toupper(c[1]) != 'P' ||
1204 toupper(c[2]) != 'I' ||
1205 c[3] != 0) {
1206 return false;
1207 }
1208
1209 // temporarily replace the first letter with \0 to
1210 // use atoi.
1211 char tmp = c[0];
1212 c[0] = '\0';
1213
1214 int d = atoi(name);
1215 c[0] = tmp;
1216
1217 if (d != 0) {
1218 if (out) out->density = d;
1219 return true;
1220 }
1221
1222 return false;
1223}
1224
1225bool AaptGroupEntry::getTouchscreenName(const char* name,
1226 ResTable_config* out)
1227{
1228 if (strcmp(name, kWildcardName) == 0) {
1229 if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
1230 return true;
1231 } else if (strcmp(name, "notouch") == 0) {
1232 if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
1233 return true;
1234 } else if (strcmp(name, "stylus") == 0) {
1235 if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
1236 return true;
1237 } else if (strcmp(name, "finger") == 0) {
1238 if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
1239 return true;
1240 }
1241
1242 return false;
1243}
1244
1245bool AaptGroupEntry::getKeysHiddenName(const char* name,
1246 ResTable_config* out)
1247{
1248 uint8_t mask = 0;
1249 uint8_t value = 0;
1250 if (strcmp(name, kWildcardName) == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001251 mask = ResTable_config::MASK_KEYSHIDDEN;
1252 value = ResTable_config::KEYSHIDDEN_ANY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 } else if (strcmp(name, "keysexposed") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001254 mask = ResTable_config::MASK_KEYSHIDDEN;
1255 value = ResTable_config::KEYSHIDDEN_NO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 } else if (strcmp(name, "keyshidden") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001257 mask = ResTable_config::MASK_KEYSHIDDEN;
1258 value = ResTable_config::KEYSHIDDEN_YES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 } else if (strcmp(name, "keyssoft") == 0) {
Kenny Rootfedfea22010-02-18 08:54:47 -08001260 mask = ResTable_config::MASK_KEYSHIDDEN;
1261 value = ResTable_config::KEYSHIDDEN_SOFT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 }
1263
1264 if (mask != 0) {
1265 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1266 return true;
1267 }
1268
1269 return false;
1270}
1271
1272bool AaptGroupEntry::getKeyboardName(const char* name,
1273 ResTable_config* out)
1274{
1275 if (strcmp(name, kWildcardName) == 0) {
1276 if (out) out->keyboard = out->KEYBOARD_ANY;
1277 return true;
1278 } else if (strcmp(name, "nokeys") == 0) {
1279 if (out) out->keyboard = out->KEYBOARD_NOKEYS;
1280 return true;
1281 } else if (strcmp(name, "qwerty") == 0) {
1282 if (out) out->keyboard = out->KEYBOARD_QWERTY;
1283 return true;
1284 } else if (strcmp(name, "12key") == 0) {
1285 if (out) out->keyboard = out->KEYBOARD_12KEY;
1286 return true;
1287 }
1288
1289 return false;
1290}
1291
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001292bool AaptGroupEntry::getNavHiddenName(const char* name,
1293 ResTable_config* out)
1294{
1295 uint8_t mask = 0;
1296 uint8_t value = 0;
1297 if (strcmp(name, kWildcardName) == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001298 mask = ResTable_config::MASK_NAVHIDDEN;
1299 value = ResTable_config::NAVHIDDEN_ANY;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001300 } else if (strcmp(name, "navexposed") == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001301 mask = ResTable_config::MASK_NAVHIDDEN;
1302 value = ResTable_config::NAVHIDDEN_NO;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001303 } else if (strcmp(name, "navhidden") == 0) {
Kenny Roote599f782010-02-19 12:45:48 -08001304 mask = ResTable_config::MASK_NAVHIDDEN;
1305 value = ResTable_config::NAVHIDDEN_YES;
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001306 }
1307
1308 if (mask != 0) {
1309 if (out) out->inputFlags = (out->inputFlags&~mask) | value;
1310 return true;
1311 }
1312
1313 return false;
1314}
1315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316bool AaptGroupEntry::getNavigationName(const char* name,
1317 ResTable_config* out)
1318{
1319 if (strcmp(name, kWildcardName) == 0) {
1320 if (out) out->navigation = out->NAVIGATION_ANY;
1321 return true;
1322 } else if (strcmp(name, "nonav") == 0) {
1323 if (out) out->navigation = out->NAVIGATION_NONAV;
1324 return true;
1325 } else if (strcmp(name, "dpad") == 0) {
1326 if (out) out->navigation = out->NAVIGATION_DPAD;
1327 return true;
1328 } else if (strcmp(name, "trackball") == 0) {
1329 if (out) out->navigation = out->NAVIGATION_TRACKBALL;
1330 return true;
1331 } else if (strcmp(name, "wheel") == 0) {
1332 if (out) out->navigation = out->NAVIGATION_WHEEL;
1333 return true;
1334 }
1335
1336 return false;
1337}
1338
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001339bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340{
1341 if (strcmp(name, kWildcardName) == 0) {
1342 if (out) {
1343 out->screenWidth = out->SCREENWIDTH_ANY;
1344 out->screenHeight = out->SCREENHEIGHT_ANY;
1345 }
1346 return true;
1347 }
1348
1349 const char* x = name;
1350 while (*x >= '0' && *x <= '9') x++;
1351 if (x == name || *x != 'x') return false;
1352 String8 xName(name, x-name);
1353 x++;
1354
1355 const char* y = x;
1356 while (*y >= '0' && *y <= '9') y++;
1357 if (y == name || *y != 0) return false;
1358 String8 yName(x, y-x);
1359
1360 uint16_t w = (uint16_t)atoi(xName.string());
1361 uint16_t h = (uint16_t)atoi(yName.string());
1362 if (w < h) {
1363 return false;
1364 }
1365
1366 if (out) {
1367 out->screenWidth = w;
1368 out->screenHeight = h;
1369 }
1370
1371 return true;
1372}
1373
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001374bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
1375{
1376 if (strcmp(name, kWildcardName) == 0) {
1377 if (out) {
1378 out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
1379 }
1380 return true;
1381 }
1382
1383 if (*name != 's') return false;
1384 name++;
1385 if (*name != 'w') return false;
1386 name++;
1387 const char* x = name;
1388 while (*x >= '0' && *x <= '9') x++;
1389 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1390 String8 xName(name, x-name);
1391
1392 if (out) {
1393 out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
1394 }
1395
1396 return true;
1397}
1398
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001399bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
1400{
1401 if (strcmp(name, kWildcardName) == 0) {
1402 if (out) {
1403 out->screenWidthDp = out->SCREENWIDTH_ANY;
1404 }
1405 return true;
1406 }
1407
1408 if (*name != 'w') return false;
1409 name++;
1410 const char* x = name;
1411 while (*x >= '0' && *x <= '9') x++;
1412 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1413 String8 xName(name, x-name);
1414
1415 if (out) {
1416 out->screenWidthDp = (uint16_t)atoi(xName.string());
1417 }
1418
1419 return true;
1420}
1421
1422bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
1423{
1424 if (strcmp(name, kWildcardName) == 0) {
1425 if (out) {
1426 out->screenHeightDp = out->SCREENWIDTH_ANY;
1427 }
1428 return true;
1429 }
1430
1431 if (*name != 'h') return false;
1432 name++;
1433 const char* x = name;
1434 while (*x >= '0' && *x <= '9') x++;
1435 if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
1436 String8 xName(name, x-name);
1437
1438 if (out) {
1439 out->screenHeightDp = (uint16_t)atoi(xName.string());
1440 }
1441
1442 return true;
1443}
1444
1445bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446{
1447 if (strcmp(name, kWildcardName) == 0) {
1448 if (out) {
1449 out->sdkVersion = out->SDKVERSION_ANY;
1450 out->minorVersion = out->MINORVERSION_ANY;
1451 }
1452 return true;
1453 }
1454
1455 if (*name != 'v') {
1456 return false;
1457 }
1458
1459 name++;
1460 const char* s = name;
1461 while (*s >= '0' && *s <= '9') s++;
1462 if (s == name || *s != 0) return false;
1463 String8 sdkName(name, s-name);
1464
1465 if (out) {
1466 out->sdkVersion = (uint16_t)atoi(sdkName.string());
1467 out->minorVersion = 0;
1468 }
1469
1470 return true;
1471}
1472
1473int AaptGroupEntry::compare(const AaptGroupEntry& o) const
1474{
1475 int v = mcc.compare(o.mcc);
1476 if (v == 0) v = mnc.compare(o.mnc);
1477 if (v == 0) v = locale.compare(o.locale);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001478 if (v == 0) v = layoutDirection.compare(o.layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 if (v == 0) v = vendor.compare(o.vendor);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001480 if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001481 if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
1482 if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001483 if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
1484 if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 if (v == 0) v = orientation.compare(o.orientation);
Tobias Haamel27b28b32010-02-09 23:09:17 +01001486 if (v == 0) v = uiModeType.compare(o.uiModeType);
1487 if (v == 0) v = uiModeNight.compare(o.uiModeNight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 if (v == 0) v = density.compare(o.density);
1489 if (v == 0) v = touchscreen.compare(o.touchscreen);
1490 if (v == 0) v = keysHidden.compare(o.keysHidden);
1491 if (v == 0) v = keyboard.compare(o.keyboard);
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001492 if (v == 0) v = navHidden.compare(o.navHidden);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 if (v == 0) v = navigation.compare(o.navigation);
1494 if (v == 0) v = screenSize.compare(o.screenSize);
1495 if (v == 0) v = version.compare(o.version);
1496 return v;
1497}
1498
Dianne Hackborne6b68032011-10-13 16:26:02 -07001499const ResTable_config& AaptGroupEntry::toParams() const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500{
Dianne Hackborne6b68032011-10-13 16:26:02 -07001501 if (!mParamsChanged) {
1502 return mParams;
1503 }
1504
1505 mParamsChanged = false;
1506 ResTable_config& params(mParams);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 memset(&params, 0, sizeof(params));
1508 getMccName(mcc.string(), &params);
1509 getMncName(mnc.string(), &params);
1510 getLocaleName(locale.string(), &params);
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001511 getLayoutDirectionName(layoutDirection.string(), &params);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001512 getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001513 getScreenWidthDpName(screenWidthDp.string(), &params);
1514 getScreenHeightDpName(screenHeightDp.string(), &params);
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001515 getScreenLayoutSizeName(screenLayoutSize.string(), &params);
1516 getScreenLayoutLongName(screenLayoutLong.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 getOrientationName(orientation.string(), &params);
Tobias Haamel27b28b32010-02-09 23:09:17 +01001518 getUiModeTypeName(uiModeType.string(), &params);
1519 getUiModeNightName(uiModeNight.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 getDensityName(density.string(), &params);
1521 getTouchscreenName(touchscreen.string(), &params);
1522 getKeysHiddenName(keysHidden.string(), &params);
1523 getKeyboardName(keyboard.string(), &params);
Dianne Hackborn93e462b2009-09-15 22:50:40 -07001524 getNavHiddenName(navHidden.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 getNavigationName(navigation.string(), &params);
1526 getScreenSizeName(screenSize.string(), &params);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 getVersionName(version.string(), &params);
Dianne Hackbornef05e072010-03-01 17:43:39 -08001528
1529 // Fix up version number based on specified parameters.
1530 int minSdk = 0;
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001531 if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
1532 || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001533 || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001534 minSdk = SDK_HONEYCOMB_MR2;
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001535 } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
Dianne Hackbornef05e072010-03-01 17:43:39 -08001536 != ResTable_config::UI_MODE_TYPE_ANY
1537 || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
1538 != ResTable_config::UI_MODE_NIGHT_ANY) {
1539 minSdk = SDK_FROYO;
1540 } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
1541 != ResTable_config::SCREENSIZE_ANY
1542 || (params.screenLayout&ResTable_config::MASK_SCREENLONG)
1543 != ResTable_config::SCREENLONG_ANY
1544 || params.density != ResTable_config::DENSITY_DEFAULT) {
1545 minSdk = SDK_DONUT;
1546 }
1547
1548 if (minSdk > params.sdkVersion) {
1549 params.sdkVersion = minSdk;
1550 }
1551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 return params;
1553}
1554
1555// =========================================================================
1556// =========================================================================
1557// =========================================================================
1558
1559void* AaptFile::editData(size_t size)
1560{
1561 if (size <= mBufferSize) {
1562 mDataSize = size;
1563 return mData;
1564 }
1565 size_t allocSize = (size*3)/2;
1566 void* buf = realloc(mData, allocSize);
1567 if (buf == NULL) {
1568 return NULL;
1569 }
1570 mData = buf;
1571 mDataSize = size;
1572 mBufferSize = allocSize;
1573 return buf;
1574}
1575
1576void* AaptFile::editData(size_t* outSize)
1577{
1578 if (outSize) {
1579 *outSize = mDataSize;
1580 }
1581 return mData;
1582}
1583
1584void* AaptFile::padData(size_t wordSize)
1585{
1586 const size_t extra = mDataSize%wordSize;
1587 if (extra == 0) {
1588 return mData;
1589 }
1590
1591 size_t initial = mDataSize;
1592 void* data = editData(initial+(wordSize-extra));
1593 if (data != NULL) {
1594 memset(((uint8_t*)data) + initial, 0, wordSize-extra);
1595 }
1596 return data;
1597}
1598
1599status_t AaptFile::writeData(const void* data, size_t size)
1600{
1601 size_t end = mDataSize;
1602 size_t total = size + end;
1603 void* buf = editData(total);
1604 if (buf == NULL) {
1605 return UNKNOWN_ERROR;
1606 }
1607 memcpy(((char*)buf)+end, data, size);
1608 return NO_ERROR;
1609}
1610
1611void AaptFile::clearData()
1612{
1613 if (mData != NULL) free(mData);
1614 mData = NULL;
1615 mDataSize = 0;
1616 mBufferSize = 0;
1617}
1618
1619String8 AaptFile::getPrintableSource() const
1620{
1621 if (hasData()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001622 String8 name(mGroupEntry.toDirName(String8()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 name.appendPath(mPath);
1624 name.append(" #generated");
1625 return name;
1626 }
1627 return mSourceFile;
1628}
1629
1630// =========================================================================
1631// =========================================================================
1632// =========================================================================
1633
Adam Lesinski09384302014-01-22 16:07:42 -08001634status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635{
Adam Lesinski09384302014-01-22 16:07:42 -08001636 ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
1637 if (index >= 0 && overwriteDuplicate) {
1638 fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
1639 mFiles[index]->getSourceFile().string(),
1640 file->getSourceFile().string());
1641 removeFile(index);
1642 index = -1;
1643 }
1644
1645 if (index < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 file->mPath = mPath;
1647 mFiles.add(file->getGroupEntry(), file);
1648 return NO_ERROR;
1649 }
1650
Dianne Hackborne6b68032011-10-13 16:26:02 -07001651#if 0
1652 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1653 file->getSourceFile().string(),
1654 file->getGroupEntry().toDirName(String8()).string(),
1655 mLeaf.string(), mPath.string());
1656#endif
1657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1659 getPrintableSource().string());
1660 return UNKNOWN_ERROR;
1661}
1662
1663void AaptGroup::removeFile(size_t index)
1664{
1665 mFiles.removeItemsAt(index);
1666}
1667
Dianne Hackborne6b68032011-10-13 16:26:02 -07001668void AaptGroup::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669{
Dianne Hackborne6b68032011-10-13 16:26:02 -07001670 printf("%s%s\n", prefix.string(), getPath().string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 const size_t N=mFiles.size();
1672 size_t i;
1673 for (i=0; i<N; i++) {
1674 sp<AaptFile> file = mFiles.valueAt(i);
1675 const AaptGroupEntry& e = file->getGroupEntry();
1676 if (file->hasData()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001677 printf("%s Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 (int)file->getSize());
1679 } else {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001680 printf("%s Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
1681 file->getPrintableSource().string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
Dianne Hackborne6b68032011-10-13 16:26:02 -07001683 //printf("%s File Group Entry: %s\n", prefix.string(),
1684 // file->getGroupEntry().toDirName(String8()).string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 }
1686}
1687
1688String8 AaptGroup::getPrintableSource() const
1689{
1690 if (mFiles.size() > 0) {
1691 // Arbitrarily pull the first source file out of the list.
1692 return mFiles.valueAt(0)->getPrintableSource();
1693 }
1694
1695 // Should never hit this case, but to be safe...
1696 return getPath();
1697
1698}
1699
1700// =========================================================================
1701// =========================================================================
1702// =========================================================================
1703
1704status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
1705{
1706 if (mFiles.indexOfKey(name) >= 0) {
1707 return ALREADY_EXISTS;
1708 }
1709 mFiles.add(name, file);
1710 return NO_ERROR;
1711}
1712
1713status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
1714{
1715 if (mDirs.indexOfKey(name) >= 0) {
1716 return ALREADY_EXISTS;
1717 }
1718 mDirs.add(name, dir);
1719 return NO_ERROR;
1720}
1721
1722sp<AaptDir> AaptDir::makeDir(const String8& path)
1723{
1724 String8 name;
1725 String8 remain = path;
1726
1727 sp<AaptDir> subdir = this;
1728 while (name = remain.walkPath(&remain), remain != "") {
1729 subdir = subdir->makeDir(name);
1730 }
1731
1732 ssize_t i = subdir->mDirs.indexOfKey(name);
1733 if (i >= 0) {
1734 return subdir->mDirs.valueAt(i);
1735 }
1736 sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
1737 subdir->mDirs.add(name, dir);
1738 return dir;
1739}
1740
1741void AaptDir::removeFile(const String8& name)
1742{
1743 mFiles.removeItem(name);
1744}
1745
1746void AaptDir::removeDir(const String8& name)
1747{
1748 mDirs.removeItem(name);
1749}
1750
Adam Lesinski09384302014-01-22 16:07:42 -08001751status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file,
1752 const bool overwrite)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753{
1754 sp<AaptGroup> group;
1755 if (mFiles.indexOfKey(leafName) >= 0) {
1756 group = mFiles.valueFor(leafName);
1757 } else {
1758 group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
1759 mFiles.add(leafName, group);
1760 }
1761
Adam Lesinski09384302014-01-22 16:07:42 -08001762 return group->addFile(file, overwrite);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763}
1764
1765ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001766 const AaptGroupEntry& kind, const String8& resType,
Adam Lesinski09384302014-01-22 16:07:42 -08001767 sp<FilePathStore>& fullResPaths, const bool overwrite)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768{
1769 Vector<String8> fileNames;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 {
1771 DIR* dir = NULL;
1772
1773 dir = opendir(srcDir.string());
1774 if (dir == NULL) {
1775 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
1776 return UNKNOWN_ERROR;
1777 }
1778
1779 /*
1780 * Slurp the filenames out of the directory.
1781 */
1782 while (1) {
1783 struct dirent* entry;
1784
1785 entry = readdir(dir);
1786 if (entry == NULL)
1787 break;
1788
1789 if (isHidden(srcDir.string(), entry->d_name))
1790 continue;
1791
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07001792 String8 name(entry->d_name);
1793 fileNames.add(name);
1794 // Add fully qualified path for dependency purposes
1795 // if we're collecting them
1796 if (fullResPaths != NULL) {
1797 fullResPaths->add(srcDir.appendPathCopy(name));
1798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 closedir(dir);
1801 }
1802
1803 ssize_t count = 0;
1804
1805 /*
1806 * Stash away the files and recursively descend into subdirectories.
1807 */
1808 const size_t N = fileNames.size();
1809 size_t i;
1810 for (i = 0; i < N; i++) {
1811 String8 pathName(srcDir);
1812 FileType type;
1813
1814 pathName.appendPath(fileNames[i].string());
1815 type = getFileType(pathName.string());
1816 if (type == kFileTypeDirectory) {
1817 sp<AaptDir> subdir;
1818 bool notAdded = false;
1819 if (mDirs.indexOfKey(fileNames[i]) >= 0) {
1820 subdir = mDirs.valueFor(fileNames[i]);
1821 } else {
1822 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
1823 notAdded = true;
1824 }
1825 ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
Adam Lesinski09384302014-01-22 16:07:42 -08001826 resType, fullResPaths, overwrite);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 if (res < NO_ERROR) {
1828 return res;
1829 }
1830 if (res > 0 && notAdded) {
1831 mDirs.add(fileNames[i], subdir);
1832 }
1833 count += res;
1834 } else if (type == kFileTypeRegular) {
1835 sp<AaptFile> file = new AaptFile(pathName, kind, resType);
Adam Lesinski09384302014-01-22 16:07:42 -08001836 status_t err = addLeafFile(fileNames[i], file, overwrite);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 if (err != NO_ERROR) {
1838 return err;
1839 }
1840
1841 count++;
1842
1843 } else {
1844 if (bundle->getVerbose())
1845 printf(" (ignoring non-file/dir '%s')\n", pathName.string());
1846 }
1847 }
1848
1849 return count;
1850}
1851
1852status_t AaptDir::validate() const
1853{
1854 const size_t NF = mFiles.size();
1855 const size_t ND = mDirs.size();
1856 size_t i;
1857 for (i = 0; i < NF; i++) {
1858 if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
1859 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1860 "Invalid filename. Unable to add.");
1861 return UNKNOWN_ERROR;
1862 }
1863
1864 size_t j;
1865 for (j = i+1; j < NF; j++) {
1866 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1867 mFiles.valueAt(j)->getLeaf().string()) == 0) {
1868 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1869 "File is case-insensitive equivalent to: %s",
1870 mFiles.valueAt(j)->getPrintableSource().string());
1871 return UNKNOWN_ERROR;
1872 }
1873
1874 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1875 // (this is mostly caught by the "marked" stuff, below)
1876 }
1877
1878 for (j = 0; j < ND; j++) {
1879 if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
1880 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1881 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
1882 "File conflicts with dir from: %s",
1883 mDirs.valueAt(j)->getPrintableSource().string());
1884 return UNKNOWN_ERROR;
1885 }
1886 }
1887 }
1888
1889 for (i = 0; i < ND; i++) {
1890 if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
1891 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1892 "Invalid directory name, unable to add.");
1893 return UNKNOWN_ERROR;
1894 }
1895
1896 size_t j;
1897 for (j = i+1; j < ND; j++) {
1898 if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
1899 mDirs.valueAt(j)->getLeaf().string()) == 0) {
1900 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
1901 "Directory is case-insensitive equivalent to: %s",
1902 mDirs.valueAt(j)->getPrintableSource().string());
1903 return UNKNOWN_ERROR;
1904 }
1905 }
1906
1907 status_t err = mDirs.valueAt(i)->validate();
1908 if (err != NO_ERROR) {
1909 return err;
1910 }
1911 }
1912
1913 return NO_ERROR;
1914}
1915
Dianne Hackborne6b68032011-10-13 16:26:02 -07001916void AaptDir::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917{
1918 const size_t ND=getDirs().size();
1919 size_t i;
1920 for (i=0; i<ND; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001921 getDirs().valueAt(i)->print(prefix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 }
1923
1924 const size_t NF=getFiles().size();
1925 for (i=0; i<NF; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07001926 getFiles().valueAt(i)->print(prefix);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 }
1928}
1929
1930String8 AaptDir::getPrintableSource() const
1931{
1932 if (mFiles.size() > 0) {
1933 // Arbitrarily pull the first file out of the list as the source dir.
1934 return mFiles.valueAt(0)->getPrintableSource().getPathDir();
1935 }
1936 if (mDirs.size() > 0) {
1937 // Or arbitrarily pull the first dir out of the list as the source dir.
1938 return mDirs.valueAt(0)->getPrintableSource().getPathDir();
1939 }
1940
1941 // Should never hit this case, but to be safe...
1942 return mPath;
1943
1944}
1945
1946// =========================================================================
1947// =========================================================================
1948// =========================================================================
1949
Dianne Hackborn1644c6d72012-02-06 15:33:21 -08001950status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
1951{
1952 status_t err = NO_ERROR;
1953 size_t N = javaSymbols->mSymbols.size();
1954 for (size_t i=0; i<N; i++) {
1955 const String8& name = javaSymbols->mSymbols.keyAt(i);
1956 const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
1957 ssize_t pos = mSymbols.indexOfKey(name);
1958 if (pos < 0) {
1959 entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
1960 err = UNKNOWN_ERROR;
1961 continue;
1962 }
1963 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1964 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1965 mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
1966 }
1967
1968 N = javaSymbols->mNestedSymbols.size();
1969 for (size_t i=0; i<N; i++) {
1970 const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
1971 const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
1972 ssize_t pos = mNestedSymbols.indexOfKey(name);
1973 if (pos < 0) {
1974 SourcePos pos;
1975 pos.error("Java symbol dir %s not defined\n", name.string());
1976 err = UNKNOWN_ERROR;
1977 continue;
1978 }
1979 //printf("**** applying java symbols in dir %s\n", name.string());
1980 status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
1981 if (myerr != NO_ERROR) {
1982 err = myerr;
1983 }
1984 }
1985
1986 return err;
1987}
1988
1989// =========================================================================
1990// =========================================================================
1991// =========================================================================
1992
Dianne Hackborne6b68032011-10-13 16:26:02 -07001993AaptAssets::AaptAssets()
1994 : AaptDir(String8(), String8()),
1995 mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
1996{
1997}
1998
1999const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
2000 if (mChanged) {
2001 }
2002 return mGroupEntries;
2003}
2004
2005status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
2006{
2007 mChanged = true;
2008 return AaptDir::addFile(name, file);
2009}
2010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011sp<AaptFile> AaptAssets::addFile(
2012 const String8& filePath, const AaptGroupEntry& entry,
2013 const String8& srcDir, sp<AaptGroup>* outGroup,
2014 const String8& resType)
2015{
2016 sp<AaptDir> dir = this;
2017 sp<AaptGroup> group;
2018 sp<AaptFile> file;
2019 String8 root, remain(filePath), partialPath;
2020 while (remain.length() > 0) {
2021 root = remain.walkPath(&remain);
2022 partialPath.appendPath(root);
2023
2024 const String8 rootStr(root);
2025
2026 if (remain.length() == 0) {
2027 ssize_t i = dir->getFiles().indexOfKey(rootStr);
2028 if (i >= 0) {
2029 group = dir->getFiles().valueAt(i);
2030 } else {
2031 group = new AaptGroup(rootStr, filePath);
2032 status_t res = dir->addFile(rootStr, group);
2033 if (res != NO_ERROR) {
2034 return NULL;
2035 }
2036 }
2037 file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
2038 status_t res = group->addFile(file);
2039 if (res != NO_ERROR) {
2040 return NULL;
2041 }
2042 break;
2043
2044 } else {
2045 ssize_t i = dir->getDirs().indexOfKey(rootStr);
2046 if (i >= 0) {
2047 dir = dir->getDirs().valueAt(i);
2048 } else {
2049 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
2050 status_t res = dir->addDir(rootStr, subdir);
2051 if (res != NO_ERROR) {
2052 return NULL;
2053 }
2054 dir = subdir;
2055 }
2056 }
2057 }
2058
2059 mGroupEntries.add(entry);
2060 if (outGroup) *outGroup = group;
2061 return file;
2062}
2063
2064void AaptAssets::addResource(const String8& leafName, const String8& path,
2065 const sp<AaptFile>& file, const String8& resType)
2066{
2067 sp<AaptDir> res = AaptDir::makeDir(kResString);
2068 String8 dirname = file->getGroupEntry().toDirName(resType);
2069 sp<AaptDir> subdir = res->makeDir(dirname);
2070 sp<AaptGroup> grr = new AaptGroup(leafName, path);
2071 grr->addFile(file);
2072
2073 subdir->addFile(leafName, grr);
2074}
2075
2076
2077ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
2078{
2079 int count;
2080 int totalCount = 0;
2081 FileType type;
2082 const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
2083 const size_t dirCount =resDirs.size();
2084 sp<AaptAssets> current = this;
2085
2086 const int N = bundle->getFileSpecCount();
2087
2088 /*
2089 * If a package manifest was specified, include that first.
2090 */
2091 if (bundle->getAndroidManifestFile() != NULL) {
2092 // place at root of zip.
2093 String8 srcFile(bundle->getAndroidManifestFile());
2094 addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
2095 NULL, String8());
2096 totalCount++;
2097 }
2098
2099 /*
2100 * If a directory of custom assets was supplied, slurp 'em up.
2101 */
Adam Lesinski09384302014-01-22 16:07:42 -08002102 const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs();
2103 const int AN = assetDirs.size();
2104 for (int i = 0; i < AN; i++) {
2105 FileType type = getFileType(assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 if (type == kFileTypeNonexistent) {
Adam Lesinski09384302014-01-22 16:07:42 -08002107 fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 return UNKNOWN_ERROR;
2109 }
2110 if (type != kFileTypeDirectory) {
Adam Lesinski09384302014-01-22 16:07:42 -08002111 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002112 return UNKNOWN_ERROR;
2113 }
2114
Adam Lesinski09384302014-01-22 16:07:42 -08002115 String8 assetRoot(assetDirs[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
2117 AaptGroupEntry group;
2118 count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
Adam Lesinski09384302014-01-22 16:07:42 -08002119 String8(), mFullAssetPaths, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 if (count < 0) {
2121 totalCount = count;
2122 goto bail;
2123 }
2124 if (count > 0) {
2125 mGroupEntries.add(group);
2126 }
2127 totalCount += count;
2128
Adam Lesinski09384302014-01-22 16:07:42 -08002129 if (bundle->getVerbose()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002130 printf("Found %d custom asset file%s in %s\n",
Adam Lesinski09384302014-01-22 16:07:42 -08002131 count, (count==1) ? "" : "s", assetDirs[i]);
2132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 }
2134
2135 /*
2136 * If a directory of resource-specific assets was supplied, slurp 'em up.
2137 */
2138 for (size_t i=0; i<dirCount; i++) {
2139 const char *res = resDirs[i];
2140 if (res) {
2141 type = getFileType(res);
2142 if (type == kFileTypeNonexistent) {
2143 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
2144 return UNKNOWN_ERROR;
2145 }
2146 if (type == kFileTypeDirectory) {
2147 if (i>0) {
2148 sp<AaptAssets> nextOverlay = new AaptAssets();
2149 current->setOverlay(nextOverlay);
2150 current = nextOverlay;
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002151 current->setFullResPaths(mFullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 }
2153 count = current->slurpResourceTree(bundle, String8(res));
2154
2155 if (count < 0) {
2156 totalCount = count;
2157 goto bail;
2158 }
2159 totalCount += count;
2160 }
2161 else {
2162 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
2163 return UNKNOWN_ERROR;
2164 }
2165 }
2166
2167 }
2168 /*
2169 * Now do any additional raw files.
2170 */
2171 for (int arg=0; arg<N; arg++) {
2172 const char* assetDir = bundle->getFileSpecEntry(arg);
2173
2174 FileType type = getFileType(assetDir);
2175 if (type == kFileTypeNonexistent) {
2176 fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
2177 return UNKNOWN_ERROR;
2178 }
2179 if (type != kFileTypeDirectory) {
2180 fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
2181 return UNKNOWN_ERROR;
2182 }
2183
2184 String8 assetRoot(assetDir);
2185
2186 if (bundle->getVerbose())
2187 printf("Processing raw dir '%s'\n", (const char*) assetDir);
2188
2189 /*
2190 * Do a recursive traversal of subdir tree. We don't make any
2191 * guarantees about ordering, so we're okay with an inorder search
2192 * using whatever order the OS happens to hand back to us.
2193 */
Josiah Gaskin03589cc2011-06-27 16:26:02 -07002194 count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 if (count < 0) {
2196 /* failure; report error and remove archive */
2197 totalCount = count;
2198 goto bail;
2199 }
2200 totalCount += count;
2201
2202 if (bundle->getVerbose())
2203 printf("Found %d asset file%s in %s\n",
2204 count, (count==1) ? "" : "s", assetDir);
2205 }
2206
2207 count = validate();
2208 if (count != NO_ERROR) {
2209 totalCount = count;
2210 goto bail;
2211 }
2212
Dianne Hackborne6b68032011-10-13 16:26:02 -07002213 count = filter(bundle);
2214 if (count != NO_ERROR) {
2215 totalCount = count;
2216 goto bail;
2217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218
2219bail:
2220 return totalCount;
2221}
2222
2223ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
2224 const AaptGroupEntry& kind,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002225 const String8& resType,
2226 sp<FilePathStore>& fullResPaths)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227{
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002228 ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 if (res > 0) {
2230 mGroupEntries.add(kind);
2231 }
2232
2233 return res;
2234}
2235
2236ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
2237{
2238 ssize_t err = 0;
2239
2240 DIR* dir = opendir(srcDir.string());
2241 if (dir == NULL) {
2242 fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
2243 return UNKNOWN_ERROR;
2244 }
2245
2246 status_t count = 0;
2247
2248 /*
2249 * Run through the directory, looking for dirs that match the
2250 * expected pattern.
2251 */
2252 while (1) {
2253 struct dirent* entry = readdir(dir);
2254 if (entry == NULL) {
2255 break;
2256 }
2257
2258 if (isHidden(srcDir.string(), entry->d_name)) {
2259 continue;
2260 }
2261
2262 String8 subdirName(srcDir);
2263 subdirName.appendPath(entry->d_name);
2264
2265 AaptGroupEntry group;
2266 String8 resType;
2267 bool b = group.initFromDirName(entry->d_name, &resType);
2268 if (!b) {
2269 fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
2270 entry->d_name);
2271 err = -1;
2272 continue;
2273 }
2274
Dianne Hackborne6b68032011-10-13 16:26:02 -07002275 if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
Ficus Kirkpatrick588f2282010-08-13 14:13:08 -07002276 int maxResInt = atoi(bundle->getMaxResVersion());
Dianne Hackborne6b68032011-10-13 16:26:02 -07002277 const char *verString = group.getVersionString().string();
Ficus Kirkpatrick588f2282010-08-13 14:13:08 -07002278 int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
2279 if (dirVersionInt > maxResInt) {
2280 fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
2281 continue;
2282 }
2283 }
2284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 FileType type = getFileType(subdirName.string());
2286
2287 if (type == kFileTypeDirectory) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002288 sp<AaptDir> dir = makeDir(resType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
Josiah Gaskin9bf34ca2011-06-14 13:57:09 -07002290 resType, mFullResPaths);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002291 if (res < 0) {
2292 count = res;
2293 goto bail;
2294 }
2295 if (res > 0) {
2296 mGroupEntries.add(group);
2297 count += res;
2298 }
2299
Dianne Hackborne6b68032011-10-13 16:26:02 -07002300 // Only add this directory if we don't already have a resource dir
2301 // for the current type. This ensures that we only add the dir once
2302 // for all configs.
2303 sp<AaptDir> rdir = resDir(resType);
2304 if (rdir == NULL) {
2305 mResDirs.add(dir);
2306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 } else {
2308 if (bundle->getVerbose()) {
2309 fprintf(stderr, " (ignoring file '%s')\n", subdirName.string());
2310 }
2311 }
2312 }
2313
2314bail:
2315 closedir(dir);
2316 dir = NULL;
2317
2318 if (err != 0) {
2319 return err;
2320 }
2321 return count;
2322}
2323
2324ssize_t
2325AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
2326{
2327 int count = 0;
2328 SortedVector<AaptGroupEntry> entries;
2329
2330 ZipFile* zip = new ZipFile;
2331 status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
2332 if (err != NO_ERROR) {
2333 fprintf(stderr, "error opening zip file %s\n", filename);
2334 count = err;
2335 delete zip;
2336 return -1;
2337 }
2338
2339 const int N = zip->getNumEntries();
2340 for (int i=0; i<N; i++) {
2341 ZipEntry* entry = zip->getEntryByIndex(i);
2342 if (entry->getDeleted()) {
2343 continue;
2344 }
2345
2346 String8 entryName(entry->getFileName());
2347
2348 String8 dirName = entryName.getPathDir();
2349 sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
2350
2351 String8 resType;
2352 AaptGroupEntry kind;
2353
2354 String8 remain;
2355 if (entryName.walkPath(&remain) == kResourceDir) {
2356 // these are the resources, pull their type out of the directory name
2357 kind.initFromDirName(remain.walkPath().string(), &resType);
2358 } else {
2359 // these are untyped and don't have an AaptGroupEntry
2360 }
2361 if (entries.indexOf(kind) < 0) {
2362 entries.add(kind);
2363 mGroupEntries.add(kind);
2364 }
2365
2366 // use the one from the zip file if they both exist.
2367 dir->removeFile(entryName.getPathLeaf());
2368
2369 sp<AaptFile> file = new AaptFile(entryName, kind, resType);
2370 status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
2371 if (err != NO_ERROR) {
2372 fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
2373 count = err;
2374 goto bail;
2375 }
2376 file->setCompressionMethod(entry->getCompressionMethod());
2377
2378#if 0
2379 if (entryName == "AndroidManifest.xml") {
2380 printf("AndroidManifest.xml\n");
2381 }
2382 printf("\n\nfile: %s\n", entryName.string());
2383#endif
2384
2385 size_t len = entry->getUncompressedLen();
2386 void* data = zip->uncompress(entry);
2387 void* buf = file->editData(len);
2388 memcpy(buf, data, len);
2389
2390#if 0
2391 const int OFF = 0;
2392 const unsigned char* p = (unsigned char*)data;
2393 const unsigned char* end = p+len;
2394 p += OFF;
2395 for (int i=0; i<32 && p < end; i++) {
2396 printf("0x%03x ", i*0x10 + OFF);
2397 for (int j=0; j<0x10 && p < end; j++) {
2398 printf(" %02x", *p);
2399 p++;
2400 }
2401 printf("\n");
2402 }
2403#endif
2404
2405 free(data);
2406
2407 count++;
2408 }
2409
2410bail:
2411 delete zip;
2412 return count;
2413}
2414
Dianne Hackborne6b68032011-10-13 16:26:02 -07002415status_t AaptAssets::filter(Bundle* bundle)
2416{
2417 ResourceFilter reqFilter;
2418 status_t err = reqFilter.parse(bundle->getConfigurations());
2419 if (err != NO_ERROR) {
2420 return err;
2421 }
2422
2423 ResourceFilter prefFilter;
2424 err = prefFilter.parse(bundle->getPreferredConfigurations());
2425 if (err != NO_ERROR) {
2426 return err;
2427 }
2428
2429 if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
2430 return NO_ERROR;
2431 }
2432
Dianne Hackbornbd9d2bc2011-10-16 14:17:07 -07002433 if (bundle->getVerbose()) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002434 if (!reqFilter.isEmpty()) {
2435 printf("Applying required filter: %s\n",
2436 bundle->getConfigurations());
2437 }
2438 if (!prefFilter.isEmpty()) {
2439 printf("Applying preferred filter: %s\n",
2440 bundle->getPreferredConfigurations());
2441 }
2442 }
2443
2444 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2445 const size_t ND = resdirs.size();
2446 for (size_t i=0; i<ND; i++) {
2447 const sp<AaptDir>& dir = resdirs.itemAt(i);
2448 if (dir->getLeaf() == kValuesDir) {
2449 // The "value" dir is special since a single file defines
2450 // multiple resources, so we can not do filtering on the
2451 // files themselves.
2452 continue;
2453 }
2454 if (dir->getLeaf() == kMipmapDir) {
2455 // We also skip the "mipmap" directory, since the point of this
2456 // is to include all densities without stripping. If you put
2457 // other configurations in here as well they won't be stripped
2458 // either... So don't do that. Seriously. What is wrong with you?
2459 continue;
2460 }
2461
2462 const size_t NG = dir->getFiles().size();
2463 for (size_t j=0; j<NG; j++) {
2464 sp<AaptGroup> grp = dir->getFiles().valueAt(j);
2465
2466 // First remove any configurations we know we don't need.
2467 for (size_t k=0; k<grp->getFiles().size(); k++) {
2468 sp<AaptFile> file = grp->getFiles().valueAt(k);
2469 if (k == 0 && grp->getFiles().size() == 1) {
2470 // If this is the only file left, we need to keep it.
2471 // Otherwise the resource IDs we are using will be inconsistent
2472 // with what we get when not stripping. Sucky, but at least
2473 // for now we can rely on the back-end doing another filtering
2474 // pass to take this out and leave us with this resource name
2475 // containing no entries.
2476 continue;
2477 }
2478 if (file->getPath().getPathExtension() == ".xml") {
2479 // We can't remove .xml files at this point, because when
2480 // we parse them they may add identifier resources, so
2481 // removing them can cause our resource identifiers to
2482 // become inconsistent.
2483 continue;
2484 }
2485 const ResTable_config& config(file->getGroupEntry().toParams());
2486 if (!reqFilter.match(config)) {
2487 if (bundle->getVerbose()) {
2488 printf("Pruning unneeded resource: %s\n",
2489 file->getPrintableSource().string());
2490 }
2491 grp->removeFile(k);
2492 k--;
2493 }
2494 }
2495
2496 // Quick check: no preferred filters, nothing more to do.
2497 if (prefFilter.isEmpty()) {
2498 continue;
2499 }
2500
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002501 // Get the preferred density if there is one. We do not match exactly for density.
2502 // If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
2503 // pick xhdpi.
2504 uint32_t preferredDensity = 0;
2505 const SortedVector<uint32_t>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
2506 if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
2507 preferredDensity = (*preferredConfigs)[0];
2508 }
2509
Dianne Hackborne6b68032011-10-13 16:26:02 -07002510 // Now deal with preferred configurations.
2511 for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
2512 for (size_t k=0; k<grp->getFiles().size(); k++) {
2513 sp<AaptFile> file = grp->getFiles().valueAt(k);
2514 if (k == 0 && grp->getFiles().size() == 1) {
2515 // If this is the only file left, we need to keep it.
2516 // Otherwise the resource IDs we are using will be inconsistent
2517 // with what we get when not stripping. Sucky, but at least
2518 // for now we can rely on the back-end doing another filtering
2519 // pass to take this out and leave us with this resource name
2520 // containing no entries.
2521 continue;
2522 }
2523 if (file->getPath().getPathExtension() == ".xml") {
2524 // We can't remove .xml files at this point, because when
2525 // we parse them they may add identifier resources, so
2526 // removing them can cause our resource identifiers to
2527 // become inconsistent.
2528 continue;
2529 }
2530 const ResTable_config& config(file->getGroupEntry().toParams());
2531 if (!prefFilter.match(axis, config)) {
2532 // This is a resource we would prefer not to have. Check
2533 // to see if have a similar variation that we would like
2534 // to have and, if so, we can drop it.
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002535
2536 uint32_t bestDensity = config.density;
2537
Dianne Hackborne6b68032011-10-13 16:26:02 -07002538 for (size_t m=0; m<grp->getFiles().size(); m++) {
2539 if (m == k) continue;
2540 sp<AaptFile> mfile = grp->getFiles().valueAt(m);
2541 const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
2542 if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002543 if (axis == AXIS_DENSITY && preferredDensity > 0) {
2544 // See if there is a better density resource
2545 if (mconfig.density < bestDensity &&
2546 mconfig.density > preferredDensity &&
2547 bestDensity > preferredDensity) {
2548 // This density is between our best density and
2549 // the preferred density, therefore it is better.
2550 bestDensity = mconfig.density;
2551 } else if (mconfig.density > bestDensity &&
2552 bestDensity < preferredDensity) {
2553 // This density is better than our best density and
2554 // our best density was smaller than our preferred
2555 // density, so it is better.
2556 bestDensity = mconfig.density;
2557 }
2558 } else if (prefFilter.match(axis, mconfig)) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002559 if (bundle->getVerbose()) {
2560 printf("Pruning unneeded resource: %s\n",
2561 file->getPrintableSource().string());
2562 }
2563 grp->removeFile(k);
2564 k--;
2565 break;
2566 }
2567 }
2568 }
Adam Lesinski9438c2d2013-10-15 17:18:51 -07002569
2570 if (axis == AXIS_DENSITY && preferredDensity > 0 &&
2571 bestDensity != config.density) {
2572 if (bundle->getVerbose()) {
2573 printf("Pruning unneeded resource: %s\n",
2574 file->getPrintableSource().string());
2575 }
2576 grp->removeFile(k);
2577 k--;
2578 }
Dianne Hackborne6b68032011-10-13 16:26:02 -07002579 }
2580 }
2581 }
2582 }
2583 }
2584
2585 return NO_ERROR;
2586}
2587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
2589{
2590 sp<AaptSymbols> sym = mSymbols.valueFor(name);
2591 if (sym == NULL) {
2592 sym = new AaptSymbols();
2593 mSymbols.add(name, sym);
2594 }
2595 return sym;
2596}
2597
Dianne Hackborn1644c6d72012-02-06 15:33:21 -08002598sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
2599{
2600 sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
2601 if (sym == NULL) {
2602 sym = new AaptSymbols();
2603 mJavaSymbols.add(name, sym);
2604 }
2605 return sym;
2606}
2607
2608status_t AaptAssets::applyJavaSymbols()
2609{
2610 size_t N = mJavaSymbols.size();
2611 for (size_t i=0; i<N; i++) {
2612 const String8& name = mJavaSymbols.keyAt(i);
2613 const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
2614 ssize_t pos = mSymbols.indexOfKey(name);
2615 if (pos < 0) {
2616 SourcePos pos;
2617 pos.error("Java symbol dir %s not defined\n", name.string());
2618 return UNKNOWN_ERROR;
2619 }
2620 //printf("**** applying java symbols in dir %s\n", name.string());
2621 status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
2622 if (err != NO_ERROR) {
2623 return err;
2624 }
2625 }
2626
2627 return NO_ERROR;
2628}
2629
2630bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
2631 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2632 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2633 // sym.isJavaSymbol ? 1 : 0);
2634 if (!mHavePrivateSymbols) return true;
2635 if (sym.isPublic) return true;
2636 if (includePrivate && sym.isJavaSymbol) return true;
2637 return false;
2638}
2639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640status_t AaptAssets::buildIncludedResources(Bundle* bundle)
2641{
2642 if (!mHaveIncludedAssets) {
2643 // Add in all includes.
2644 const Vector<const char*>& incl = bundle->getPackageIncludes();
2645 const size_t N=incl.size();
2646 for (size_t i=0; i<N; i++) {
2647 if (bundle->getVerbose())
2648 printf("Including resources from package: %s\n", incl[i]);
2649 if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
2650 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
2651 incl[i]);
2652 return UNKNOWN_ERROR;
2653 }
2654 }
2655 mHaveIncludedAssets = true;
2656 }
2657
2658 return NO_ERROR;
2659}
2660
2661status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
2662{
2663 const ResTable& res = getIncludedResources();
2664 // XXX dirty!
Narayan Kamath7c4887f2014-01-27 17:32:37 +00002665 return const_cast<ResTable&>(res).add(file->getData(), file->getSize());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002666}
2667
2668const ResTable& AaptAssets::getIncludedResources() const
2669{
2670 return mIncludedAssets.getResources(false);
2671}
2672
Dianne Hackborne6b68032011-10-13 16:26:02 -07002673void AaptAssets::print(const String8& prefix) const
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674{
Dianne Hackborne6b68032011-10-13 16:26:02 -07002675 String8 innerPrefix(prefix);
2676 innerPrefix.append(" ");
2677 String8 innerInnerPrefix(innerPrefix);
2678 innerInnerPrefix.append(" ");
2679 printf("%sConfigurations:\n", prefix.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 const size_t N=mGroupEntries.size();
2681 for (size_t i=0; i<N; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002682 String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
2683 printf("%s %s\n", prefix.string(),
2684 cname != "" ? cname.string() : "(default)");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
2686
Dianne Hackborne6b68032011-10-13 16:26:02 -07002687 printf("\n%sFiles:\n", prefix.string());
2688 AaptDir::print(innerPrefix);
2689
2690 printf("\n%sResource Dirs:\n", prefix.string());
2691 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2692 const size_t NR = resdirs.size();
2693 for (size_t i=0; i<NR; i++) {
2694 const sp<AaptDir>& d = resdirs.itemAt(i);
2695 printf("%s Type %s\n", prefix.string(), d->getLeaf().string());
2696 d->print(innerInnerPrefix);
2697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698}
2699
Dianne Hackborne6b68032011-10-13 16:26:02 -07002700sp<AaptDir> AaptAssets::resDir(const String8& name) const
Joe Onorato1553c822009-08-30 13:36:22 -07002701{
Dianne Hackborne6b68032011-10-13 16:26:02 -07002702 const Vector<sp<AaptDir> >& resdirs = mResDirs;
2703 const size_t N = resdirs.size();
Joe Onorato1553c822009-08-30 13:36:22 -07002704 for (size_t i=0; i<N; i++) {
Dianne Hackborne6b68032011-10-13 16:26:02 -07002705 const sp<AaptDir>& d = resdirs.itemAt(i);
Joe Onorato1553c822009-08-30 13:36:22 -07002706 if (d->getLeaf() == name) {
2707 return d;
2708 }
2709 }
2710 return NULL;
2711}
2712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713bool
2714valid_symbol_name(const String8& symbol)
2715{
2716 static char const * const KEYWORDS[] = {
2717 "abstract", "assert", "boolean", "break",
2718 "byte", "case", "catch", "char", "class", "const", "continue",
2719 "default", "do", "double", "else", "enum", "extends", "final",
2720 "finally", "float", "for", "goto", "if", "implements", "import",
2721 "instanceof", "int", "interface", "long", "native", "new", "package",
2722 "private", "protected", "public", "return", "short", "static",
2723 "strictfp", "super", "switch", "synchronized", "this", "throw",
2724 "throws", "transient", "try", "void", "volatile", "while",
2725 "true", "false", "null",
2726 NULL
2727 };
2728 const char*const* k = KEYWORDS;
2729 const char*const s = symbol.string();
2730 while (*k) {
2731 if (0 == strcmp(s, *k)) {
2732 return false;
2733 }
2734 k++;
2735 }
2736 return true;
2737}