2 // Copyright 2006 The Android Open Source Project
5 #include "AaptAssets.h"
6 #include "ResourceFilter.h"
9 #include <utils/misc.h>
10 #include <utils/SortedVector.h>
16 static const char* kDefaultLocale
= "default";
17 static const char* kWildcardName
= "any";
18 static const char* kAssetDir
= "assets";
19 static const char* kResourceDir
= "res";
20 static const char* kValuesDir
= "values";
21 static const char* kMipmapDir
= "mipmap";
22 static const char* kInvalidChars
= "/\\:";
23 static const size_t kMaxAssetFileName
= 100;
25 static const String8
kResString(kResourceDir
);
28 * Names of asset files must meet the following criteria:
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 { '/' '\\' ':' }
35 * Pass in just the filename, not the full path.
37 static bool validateFileName(const char* fileName
)
39 const char* cp
= fileName
;
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
53 if (len
< 1 || len
> kMaxAssetFileName
)
54 return false; // reject empty or too long
59 // The default to use if no other ignore pattern is defined.
60 const char * const gDefaultIgnoreAssets
=
61 "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~";
62 // The ignore pattern that can be passed via --ignore-assets in Main.cpp
63 const char * gUserIgnoreAssets
= NULL
;
65 static bool isHidden(const char *root
, const char *path
)
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.
80 if (strcmp(path
, ".") == 0 || strcmp(path
, "..") == 0) {
84 const char *delim
= ":";
85 const char *p
= gUserIgnoreAssets
;
87 p
= getenv("ANDROID_AAPT_IGNORE");
90 p
= gDefaultIgnoreAssets
;
92 char *patterns
= strdup(p
);
96 char *matchedPattern
= NULL
;
98 String8
fullPath(root
);
99 fullPath
.appendPath(path
);
100 FileType type
= getFileType(fullPath
);
102 int plen
= strlen(path
);
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;
114 if (strncasecmp(token
, "<file>", 6) == 0) {
115 if (type
!= kFileTypeRegular
) continue;
119 matchedPattern
= token
;
120 int n
= strlen(token
);
122 if (token
[0] == '*') {
127 ignore
= strncasecmp(token
, path
+ plen
- n
, n
) == 0;
129 } else if (n
> 1 && token
[n
- 1] == '*') {
131 ignore
= strncasecmp(token
, path
, n
- 1) == 0;
133 ignore
= strcasecmp(token
, path
) == 0;
137 if (ignore
&& chatty
) {
138 fprintf(stderr
, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
139 type
== kFileTypeDirectory
? "dir" : "file",
141 matchedPattern
? matchedPattern
: "");
148 // =========================================================================
149 // =========================================================================
150 // =========================================================================
153 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
)
155 ResTable_config config
;
158 if (getMccName(part
.string(), &config
)) {
165 if (getMncName(part
.string(), &config
)) {
172 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
173 *axis
= AXIS_LANGUAGE
;
174 *value
= part
[1] << 8 | part
[0];
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]);
187 if (getLayoutDirectionName(part
.string(), &config
)) {
188 *axis
= AXIS_LAYOUTDIR
;
189 *value
= (config
.screenLayout
&ResTable_config::MASK_LAYOUTDIR
);
193 // smallest screen dp width
194 if (getSmallestScreenWidthDpName(part
.string(), &config
)) {
195 *axis
= AXIS_SMALLESTSCREENWIDTHDP
;
196 *value
= config
.smallestScreenWidthDp
;
201 if (getScreenWidthDpName(part
.string(), &config
)) {
202 *axis
= AXIS_SCREENWIDTHDP
;
203 *value
= config
.screenWidthDp
;
208 if (getScreenHeightDpName(part
.string(), &config
)) {
209 *axis
= AXIS_SCREENHEIGHTDP
;
210 *value
= config
.screenHeightDp
;
214 // screen layout size
215 if (getScreenLayoutSizeName(part
.string(), &config
)) {
216 *axis
= AXIS_SCREENLAYOUTSIZE
;
217 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
221 // screen layout long
222 if (getScreenLayoutLongName(part
.string(), &config
)) {
223 *axis
= AXIS_SCREENLAYOUTLONG
;
224 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
229 if (getOrientationName(part
.string(), &config
)) {
230 *axis
= AXIS_ORIENTATION
;
231 *value
= config
.orientation
;
236 if (getUiModeTypeName(part
.string(), &config
)) {
237 *axis
= AXIS_UIMODETYPE
;
238 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
243 if (getUiModeNightName(part
.string(), &config
)) {
244 *axis
= AXIS_UIMODENIGHT
;
245 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
250 if (getDensityName(part
.string(), &config
)) {
251 *axis
= AXIS_DENSITY
;
252 *value
= config
.density
;
257 if (getTouchscreenName(part
.string(), &config
)) {
258 *axis
= AXIS_TOUCHSCREEN
;
259 *value
= config
.touchscreen
;
264 if (getKeysHiddenName(part
.string(), &config
)) {
265 *axis
= AXIS_KEYSHIDDEN
;
266 *value
= config
.inputFlags
;
271 if (getKeyboardName(part
.string(), &config
)) {
272 *axis
= AXIS_KEYBOARD
;
273 *value
= config
.keyboard
;
278 if (getNavHiddenName(part
.string(), &config
)) {
279 *axis
= AXIS_NAVHIDDEN
;
280 *value
= config
.inputFlags
;
285 if (getNavigationName(part
.string(), &config
)) {
286 *axis
= AXIS_NAVIGATION
;
287 *value
= config
.navigation
;
292 if (getScreenSizeName(part
.string(), &config
)) {
293 *axis
= AXIS_SCREENSIZE
;
294 *value
= config
.screenSize
;
299 if (getVersionName(part
.string(), &config
)) {
300 *axis
= AXIS_VERSION
;
301 *value
= config
.version
;
309 AaptGroupEntry::getConfigValueForAxis(const ResTable_config
& config
, int axis
)
317 return (((uint32_t)config
.country
[1]) << 24) | (((uint32_t)config
.country
[0]) << 16)
318 | (((uint32_t)config
.language
[1]) << 8) | (config
.language
[0]);
320 return config
.screenLayout
&ResTable_config::MASK_LAYOUTDIR
;
321 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
);
330 return config
.density
;
331 case AXIS_TOUCHSCREEN
:
332 return config
.touchscreen
;
333 case AXIS_KEYSHIDDEN
:
334 return config
.inputFlags
;
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
;
348 return config
.version
;
354 AaptGroupEntry::configSameExcept(const ResTable_config
& config
,
355 const ResTable_config
& otherConfig
, int axis
)
357 for (int i
=AXIS_START
; i
<=AXIS_END
; i
++) {
361 if (getConfigValueForAxis(config
, i
) != getConfigValueForAxis(otherConfig
, i
)) {
369 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
371 mParamsChanged
= true;
373 Vector
<String8
> parts
;
375 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
376 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, layoutDir
, vers
;
377 String8 uiModeType
, uiModeNight
, smallestwidthdp
, widthdp
, heightdp
;
381 while (NULL
!= (q
= strchr(p
, '-'))) {
385 //printf("part: %s\n", parts[parts.size()-1].string());
391 //printf("part: %s\n", parts[parts.size()-1].string());
393 const int N
= parts
.size();
395 String8 part
= parts
[index
];
398 if (!isValidResourceType(part
)) {
410 if (getMccName(part
.string())) {
419 //printf("not mcc: %s\n", part.string());
423 if (getMncName(part
.string())) {
432 //printf("not mcc: %s\n", part.string());
436 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
445 //printf("not language: %s\n", part.string());
450 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
453 loc
+= part
.string() + 1;
461 //printf("not region: %s\n", part.string());
464 if (getLayoutDirectionName(part
.string())) {
473 //printf("not layout direction: %s\n", part.string());
476 if (getSmallestScreenWidthDpName(part
.string())) {
477 smallestwidthdp
= part
;
485 //printf("not smallest screen width dp: %s\n", part.string());
488 if (getScreenWidthDpName(part
.string())) {
497 //printf("not screen width dp: %s\n", part.string());
500 if (getScreenHeightDpName(part
.string())) {
509 //printf("not screen height dp: %s\n", part.string());
512 if (getScreenLayoutSizeName(part
.string())) {
521 //printf("not screen layout size: %s\n", part.string());
524 if (getScreenLayoutLongName(part
.string())) {
533 //printf("not screen layout long: %s\n", part.string());
537 if (getOrientationName(part
.string())) {
546 //printf("not orientation: %s\n", part.string());
550 if (getUiModeTypeName(part
.string())) {
559 //printf("not ui mode type: %s\n", part.string());
563 if (getUiModeNightName(part
.string())) {
572 //printf("not ui mode night: %s\n", part.string());
576 if (getDensityName(part
.string())) {
585 //printf("not density: %s\n", part.string());
589 if (getTouchscreenName(part
.string())) {
598 //printf("not touchscreen: %s\n", part.string());
602 if (getKeysHiddenName(part
.string())) {
611 //printf("not keysHidden: %s\n", part.string());
615 if (getKeyboardName(part
.string())) {
624 //printf("not keyboard: %s\n", part.string());
628 if (getNavHiddenName(part
.string())) {
637 //printf("not navHidden: %s\n", part.string());
640 if (getNavigationName(part
.string())) {
649 //printf("not navigation: %s\n", part.string());
652 if (getScreenSizeName(part
.string())) {
661 //printf("not screen size: %s\n", part.string());
664 if (getVersionName(part
.string())) {
673 //printf("not version: %s\n", part.string());
676 // if there are extra parts, it doesn't match
683 this->screenLayoutSize
= layoutsize
;
684 this->screenLayoutLong
= layoutlong
;
685 this->smallestScreenWidthDp
= smallestwidthdp
;
686 this->screenWidthDp
= widthdp
;
687 this->screenHeightDp
= heightdp
;
688 this->orientation
= orient
;
689 this->uiModeType
= uiModeType
;
690 this->uiModeNight
= uiModeNight
;
692 this->touchscreen
= touch
;
693 this->keysHidden
= keysHidden
;
694 this->keyboard
= key
;
695 this->navHidden
= navHidden
;
696 this->navigation
= nav
;
697 this->screenSize
= size
;
698 this->layoutDirection
= layoutDir
;
699 this->version
= vers
;
701 // what is this anyway?
708 AaptGroupEntry::toString() const
710 String8 s
= this->mcc
;
716 s
+= layoutDirection
;
718 s
+= smallestScreenWidthDp
;
724 s
+= screenLayoutSize
;
726 s
+= screenLayoutLong
;
728 s
+= this->orientation
;
753 AaptGroupEntry::toDirName(const String8
& resType
) const
756 if (this->mcc
!= "") {
757 if (s
.length() > 0) {
762 if (this->mnc
!= "") {
763 if (s
.length() > 0) {
768 if (this->locale
!= "") {
769 if (s
.length() > 0) {
774 if (this->layoutDirection
!= "") {
775 if (s
.length() > 0) {
778 s
+= layoutDirection
;
780 if (this->smallestScreenWidthDp
!= "") {
781 if (s
.length() > 0) {
784 s
+= smallestScreenWidthDp
;
786 if (this->screenWidthDp
!= "") {
787 if (s
.length() > 0) {
792 if (this->screenHeightDp
!= "") {
793 if (s
.length() > 0) {
798 if (this->screenLayoutSize
!= "") {
799 if (s
.length() > 0) {
802 s
+= screenLayoutSize
;
804 if (this->screenLayoutLong
!= "") {
805 if (s
.length() > 0) {
808 s
+= screenLayoutLong
;
810 if (this->orientation
!= "") {
811 if (s
.length() > 0) {
816 if (this->uiModeType
!= "") {
817 if (s
.length() > 0) {
822 if (this->uiModeNight
!= "") {
823 if (s
.length() > 0) {
828 if (this->density
!= "") {
829 if (s
.length() > 0) {
834 if (this->touchscreen
!= "") {
835 if (s
.length() > 0) {
840 if (this->keysHidden
!= "") {
841 if (s
.length() > 0) {
846 if (this->keyboard
!= "") {
847 if (s
.length() > 0) {
852 if (this->navHidden
!= "") {
853 if (s
.length() > 0) {
858 if (this->navigation
!= "") {
859 if (s
.length() > 0) {
864 if (this->screenSize
!= "") {
865 if (s
.length() > 0) {
870 if (this->version
!= "") {
871 if (s
.length() > 0) {
880 bool AaptGroupEntry::getMccName(const char* name
,
881 ResTable_config
* out
)
883 if (strcmp(name
, kWildcardName
) == 0) {
884 if (out
) out
->mcc
= 0;
887 const char* c
= name
;
888 if (tolower(*c
) != 'm') return false;
890 if (tolower(*c
) != 'c') return false;
892 if (tolower(*c
) != 'c') return false;
897 while (*c
>= '0' && *c
<= '9') {
900 if (*c
!= 0) return false;
901 if (c
-val
!= 3) return false;
905 if (out
) out
->mcc
= d
;
912 bool AaptGroupEntry::getMncName(const char* name
,
913 ResTable_config
* out
)
915 if (strcmp(name
, kWildcardName
) == 0) {
916 if (out
) out
->mcc
= 0;
919 const char* c
= name
;
920 if (tolower(*c
) != 'm') return false;
922 if (tolower(*c
) != 'n') return false;
924 if (tolower(*c
) != 'c') return false;
929 while (*c
>= '0' && *c
<= '9') {
932 if (*c
!= 0) return false;
933 if (c
-val
== 0 || c
-val
> 3) return false;
936 out
->mnc
= atoi(val
);
943 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
946 * TODO: Should insist that the first two letters are lower case, and the
947 * second two are upper.
949 bool AaptGroupEntry::getLocaleName(const char* fileName
,
950 ResTable_config
* out
)
952 if (strcmp(fileName
, kWildcardName
) == 0
953 || strcmp(fileName
, kDefaultLocale
) == 0) {
955 out
->language
[0] = 0;
956 out
->language
[1] = 0;
963 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
965 out
->language
[0] = fileName
[0];
966 out
->language
[1] = fileName
[1];
973 if (strlen(fileName
) == 5 &&
974 isalpha(fileName
[0]) &&
975 isalpha(fileName
[1]) &&
976 fileName
[2] == '-' &&
977 isalpha(fileName
[3]) &&
978 isalpha(fileName
[4])) {
980 out
->language
[0] = fileName
[0];
981 out
->language
[1] = fileName
[1];
982 out
->country
[0] = fileName
[3];
983 out
->country
[1] = fileName
[4];
991 bool AaptGroupEntry::getLayoutDirectionName(const char* name
, ResTable_config
* out
)
993 if (strcmp(name
, kWildcardName
) == 0) {
994 if (out
) out
->screenLayout
=
995 (out
->screenLayout
&~ResTable_config::MASK_LAYOUTDIR
)
996 | ResTable_config::LAYOUTDIR_ANY
;
998 } else if (strcmp(name
, "ldltr") == 0) {
999 if (out
) out
->screenLayout
=
1000 (out
->screenLayout
&~ResTable_config::MASK_LAYOUTDIR
)
1001 | ResTable_config::LAYOUTDIR_LTR
;
1003 } else if (strcmp(name
, "ldrtl") == 0) {
1004 if (out
) out
->screenLayout
=
1005 (out
->screenLayout
&~ResTable_config::MASK_LAYOUTDIR
)
1006 | ResTable_config::LAYOUTDIR_RTL
;
1013 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
1014 ResTable_config
* out
)
1016 if (strcmp(name
, kWildcardName
) == 0) {
1017 if (out
) out
->screenLayout
=
1018 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
1019 | ResTable_config::SCREENSIZE_ANY
;
1021 } else if (strcmp(name
, "small") == 0) {
1022 if (out
) out
->screenLayout
=
1023 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
1024 | ResTable_config::SCREENSIZE_SMALL
;
1026 } else if (strcmp(name
, "normal") == 0) {
1027 if (out
) out
->screenLayout
=
1028 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
1029 | ResTable_config::SCREENSIZE_NORMAL
;
1031 } else if (strcmp(name
, "large") == 0) {
1032 if (out
) out
->screenLayout
=
1033 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
1034 | ResTable_config::SCREENSIZE_LARGE
;
1036 } else if (strcmp(name
, "xlarge") == 0) {
1037 if (out
) out
->screenLayout
=
1038 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
1039 | ResTable_config::SCREENSIZE_XLARGE
;
1046 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
1047 ResTable_config
* out
)
1049 if (strcmp(name
, kWildcardName
) == 0) {
1050 if (out
) out
->screenLayout
=
1051 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1052 | ResTable_config::SCREENLONG_ANY
;
1054 } else if (strcmp(name
, "long") == 0) {
1055 if (out
) out
->screenLayout
=
1056 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1057 | ResTable_config::SCREENLONG_YES
;
1059 } else if (strcmp(name
, "notlong") == 0) {
1060 if (out
) out
->screenLayout
=
1061 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1062 | ResTable_config::SCREENLONG_NO
;
1069 bool AaptGroupEntry::getOrientationName(const char* name
,
1070 ResTable_config
* out
)
1072 if (strcmp(name
, kWildcardName
) == 0) {
1073 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
1075 } else if (strcmp(name
, "port") == 0) {
1076 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
1078 } else if (strcmp(name
, "land") == 0) {
1079 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
1081 } else if (strcmp(name
, "square") == 0) {
1082 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
1089 bool AaptGroupEntry::getUiModeTypeName(const char* name
,
1090 ResTable_config
* out
)
1092 if (strcmp(name
, kWildcardName
) == 0) {
1093 if (out
) out
->uiMode
=
1094 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1095 | ResTable_config::UI_MODE_TYPE_ANY
;
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
;
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
;
1107 } 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
;
1112 } 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
;
1122 bool AaptGroupEntry::getUiModeNightName(const char* name
,
1123 ResTable_config
* out
)
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
;
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
;
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
;
1145 bool AaptGroupEntry::getDensityName(const char* name
,
1146 ResTable_config
* out
)
1148 if (strcmp(name
, kWildcardName
) == 0) {
1149 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
1153 if (strcmp(name
, "nodpi") == 0) {
1154 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
1158 if (strcmp(name
, "ldpi") == 0) {
1159 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
1163 if (strcmp(name
, "mdpi") == 0) {
1164 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
1168 if (strcmp(name
, "tvdpi") == 0) {
1169 if (out
) out
->density
= ResTable_config::DENSITY_TV
;
1173 if (strcmp(name
, "hdpi") == 0) {
1174 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
1178 if (strcmp(name
, "xhdpi") == 0) {
1179 if (out
) out
->density
= ResTable_config::DENSITY_XHIGH
;
1183 if (strcmp(name
, "xxhdpi") == 0) {
1184 if (out
) out
->density
= ResTable_config::DENSITY_XXHIGH
;
1188 char* c
= (char*)name
;
1189 while (*c
>= '0' && *c
<= '9') {
1193 // check that we have 'dpi' after the last digit.
1194 if (toupper(c
[0]) != 'D' ||
1195 toupper(c
[1]) != 'P' ||
1196 toupper(c
[2]) != 'I' ||
1201 // temporarily replace the first letter with \0 to
1210 if (out
) out
->density
= d
;
1217 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1218 ResTable_config
* out
)
1220 if (strcmp(name
, kWildcardName
) == 0) {
1221 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1223 } else if (strcmp(name
, "notouch") == 0) {
1224 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1226 } else if (strcmp(name
, "stylus") == 0) {
1227 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1229 } else if (strcmp(name
, "finger") == 0) {
1230 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1237 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1238 ResTable_config
* out
)
1242 if (strcmp(name
, kWildcardName
) == 0) {
1243 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1244 value
= ResTable_config::KEYSHIDDEN_ANY
;
1245 } else if (strcmp(name
, "keysexposed") == 0) {
1246 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1247 value
= ResTable_config::KEYSHIDDEN_NO
;
1248 } else if (strcmp(name
, "keyshidden") == 0) {
1249 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1250 value
= ResTable_config::KEYSHIDDEN_YES
;
1251 } else if (strcmp(name
, "keyssoft") == 0) {
1252 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1253 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1257 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1264 bool AaptGroupEntry::getKeyboardName(const char* name
,
1265 ResTable_config
* out
)
1267 if (strcmp(name
, kWildcardName
) == 0) {
1268 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1270 } else if (strcmp(name
, "nokeys") == 0) {
1271 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1273 } else if (strcmp(name
, "qwerty") == 0) {
1274 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1276 } else if (strcmp(name
, "12key") == 0) {
1277 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1284 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1285 ResTable_config
* out
)
1289 if (strcmp(name
, kWildcardName
) == 0) {
1290 mask
= ResTable_config::MASK_NAVHIDDEN
;
1291 value
= ResTable_config::NAVHIDDEN_ANY
;
1292 } else if (strcmp(name
, "navexposed") == 0) {
1293 mask
= ResTable_config::MASK_NAVHIDDEN
;
1294 value
= ResTable_config::NAVHIDDEN_NO
;
1295 } else if (strcmp(name
, "navhidden") == 0) {
1296 mask
= ResTable_config::MASK_NAVHIDDEN
;
1297 value
= ResTable_config::NAVHIDDEN_YES
;
1301 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1308 bool AaptGroupEntry::getNavigationName(const char* name
,
1309 ResTable_config
* out
)
1311 if (strcmp(name
, kWildcardName
) == 0) {
1312 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1314 } else if (strcmp(name
, "nonav") == 0) {
1315 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1317 } else if (strcmp(name
, "dpad") == 0) {
1318 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1320 } else if (strcmp(name
, "trackball") == 0) {
1321 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1323 } else if (strcmp(name
, "wheel") == 0) {
1324 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1331 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1333 if (strcmp(name
, kWildcardName
) == 0) {
1335 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1336 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1341 const char* x
= name
;
1342 while (*x
>= '0' && *x
<= '9') x
++;
1343 if (x
== name
|| *x
!= 'x') return false;
1344 String8
xName(name
, x
-name
);
1348 while (*y
>= '0' && *y
<= '9') y
++;
1349 if (y
== name
|| *y
!= 0) return false;
1350 String8
yName(x
, y
-x
);
1352 uint16_t w
= (uint16_t)atoi(xName
.string());
1353 uint16_t h
= (uint16_t)atoi(yName
.string());
1359 out
->screenWidth
= w
;
1360 out
->screenHeight
= h
;
1366 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1368 if (strcmp(name
, kWildcardName
) == 0) {
1370 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1375 if (*name
!= 's') return false;
1377 if (*name
!= 'w') return false;
1379 const char* x
= name
;
1380 while (*x
>= '0' && *x
<= '9') x
++;
1381 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1382 String8
xName(name
, x
-name
);
1385 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1391 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1393 if (strcmp(name
, kWildcardName
) == 0) {
1395 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1400 if (*name
!= 'w') return false;
1402 const char* x
= name
;
1403 while (*x
>= '0' && *x
<= '9') x
++;
1404 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1405 String8
xName(name
, x
-name
);
1408 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1414 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1416 if (strcmp(name
, kWildcardName
) == 0) {
1418 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1423 if (*name
!= 'h') return false;
1425 const char* x
= name
;
1426 while (*x
>= '0' && *x
<= '9') x
++;
1427 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1428 String8
xName(name
, x
-name
);
1431 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1437 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1439 if (strcmp(name
, kWildcardName
) == 0) {
1441 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1442 out
->minorVersion
= out
->MINORVERSION_ANY
;
1452 const char* s
= name
;
1453 while (*s
>= '0' && *s
<= '9') s
++;
1454 if (s
== name
|| *s
!= 0) return false;
1455 String8
sdkName(name
, s
-name
);
1458 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1459 out
->minorVersion
= 0;
1465 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1467 int v
= mcc
.compare(o
.mcc
);
1468 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1469 if (v
== 0) v
= locale
.compare(o
.locale
);
1470 if (v
== 0) v
= layoutDirection
.compare(o
.layoutDirection
);
1471 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1472 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1473 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1474 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1475 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1476 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1477 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1478 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1479 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1480 if (v
== 0) v
= density
.compare(o
.density
);
1481 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1482 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1483 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1484 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1485 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1486 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1487 if (v
== 0) v
= version
.compare(o
.version
);
1491 const ResTable_config
& AaptGroupEntry::toParams() const
1493 if (!mParamsChanged
) {
1497 mParamsChanged
= false;
1498 ResTable_config
& params(mParams
);
1499 memset(¶ms
, 0, sizeof(params
));
1500 getMccName(mcc
.string(), ¶ms
);
1501 getMncName(mnc
.string(), ¶ms
);
1502 getLocaleName(locale
.string(), ¶ms
);
1503 getLayoutDirectionName(layoutDirection
.string(), ¶ms
);
1504 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1505 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1506 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1507 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1508 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1509 getOrientationName(orientation
.string(), ¶ms
);
1510 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1511 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1512 getDensityName(density
.string(), ¶ms
);
1513 getTouchscreenName(touchscreen
.string(), ¶ms
);
1514 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1515 getKeyboardName(keyboard
.string(), ¶ms
);
1516 getNavHiddenName(navHidden
.string(), ¶ms
);
1517 getNavigationName(navigation
.string(), ¶ms
);
1518 getScreenSizeName(screenSize
.string(), ¶ms
);
1519 getVersionName(version
.string(), ¶ms
);
1521 // Fix up version number based on specified parameters.
1523 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1524 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1525 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1526 minSdk
= SDK_HONEYCOMB_MR2
;
1527 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1528 != ResTable_config::UI_MODE_TYPE_ANY
1529 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1530 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1532 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1533 != ResTable_config::SCREENSIZE_ANY
1534 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1535 != ResTable_config::SCREENLONG_ANY
1536 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1540 if (minSdk
> params
.sdkVersion
) {
1541 params
.sdkVersion
= minSdk
;
1547 // =========================================================================
1548 // =========================================================================
1549 // =========================================================================
1551 void* AaptFile::editData(size_t size
)
1553 if (size
<= mBufferSize
) {
1557 size_t allocSize
= (size
*3)/2;
1558 void* buf
= realloc(mData
, allocSize
);
1564 mBufferSize
= allocSize
;
1568 void* AaptFile::editData(size_t* outSize
)
1571 *outSize
= mDataSize
;
1576 void* AaptFile::padData(size_t wordSize
)
1578 const size_t extra
= mDataSize%wordSize
;
1583 size_t initial
= mDataSize
;
1584 void* data
= editData(initial
+(wordSize
-extra
));
1586 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1591 status_t
AaptFile::writeData(const void* data
, size_t size
)
1593 size_t end
= mDataSize
;
1594 size_t total
= size
+ end
;
1595 void* buf
= editData(total
);
1597 return UNKNOWN_ERROR
;
1599 memcpy(((char*)buf
)+end
, data
, size
);
1603 void AaptFile::clearData()
1605 if (mData
!= NULL
) free(mData
);
1611 String8
AaptFile::getPrintableSource() const
1614 String8
name(mGroupEntry
.toDirName(String8()));
1615 name
.appendPath(mPath
);
1616 name
.append(" #generated");
1622 // =========================================================================
1623 // =========================================================================
1624 // =========================================================================
1626 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1628 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1629 file
->mPath
= mPath
;
1630 mFiles
.add(file
->getGroupEntry(), file
);
1635 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1636 file
->getSourceFile().string(),
1637 file
->getGroupEntry().toDirName(String8()).string(),
1638 mLeaf
.string(), mPath
.string());
1641 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1642 getPrintableSource().string());
1643 return UNKNOWN_ERROR
;
1646 void AaptGroup::removeFile(size_t index
)
1648 mFiles
.removeItemsAt(index
);
1651 void AaptGroup::print(const String8
& prefix
) const
1653 printf("%s%s\n", prefix
.string(), getPath().string());
1654 const size_t N
=mFiles
.size();
1656 for (i
=0; i
<N
; i
++) {
1657 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1658 const AaptGroupEntry
& e
= file
->getGroupEntry();
1659 if (file
->hasData()) {
1660 printf("%s Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(),
1661 (int)file
->getSize());
1663 printf("%s Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(),
1664 file
->getPrintableSource().string());
1666 //printf("%s File Group Entry: %s\n", prefix.string(),
1667 // file->getGroupEntry().toDirName(String8()).string());
1671 String8
AaptGroup::getPrintableSource() const
1673 if (mFiles
.size() > 0) {
1674 // Arbitrarily pull the first source file out of the list.
1675 return mFiles
.valueAt(0)->getPrintableSource();
1678 // Should never hit this case, but to be safe...
1683 // =========================================================================
1684 // =========================================================================
1685 // =========================================================================
1687 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1689 if (mFiles
.indexOfKey(name
) >= 0) {
1690 return ALREADY_EXISTS
;
1692 mFiles
.add(name
, file
);
1696 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1698 if (mDirs
.indexOfKey(name
) >= 0) {
1699 return ALREADY_EXISTS
;
1701 mDirs
.add(name
, dir
);
1705 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1708 String8 remain
= path
;
1710 sp
<AaptDir
> subdir
= this;
1711 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1712 subdir
= subdir
->makeDir(name
);
1715 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1717 return subdir
->mDirs
.valueAt(i
);
1719 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1720 subdir
->mDirs
.add(name
, dir
);
1724 void AaptDir::removeFile(const String8
& name
)
1726 mFiles
.removeItem(name
);
1729 void AaptDir::removeDir(const String8
& name
)
1731 mDirs
.removeItem(name
);
1734 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1736 sp
<AaptGroup
> group
;
1737 if (mFiles
.indexOfKey(leafName
) >= 0) {
1738 group
= mFiles
.valueFor(leafName
);
1740 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1741 mFiles
.add(leafName
, group
);
1744 return group
->addFile(file
);
1747 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1748 const AaptGroupEntry
& kind
, const String8
& resType
,
1749 sp
<FilePathStore
>& fullResPaths
)
1751 Vector
<String8
> fileNames
;
1755 dir
= opendir(srcDir
.string());
1757 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1758 return UNKNOWN_ERROR
;
1762 * Slurp the filenames out of the directory.
1765 struct dirent
* entry
;
1767 entry
= readdir(dir
);
1771 if (isHidden(srcDir
.string(), entry
->d_name
))
1774 String8
name(entry
->d_name
);
1775 fileNames
.add(name
);
1776 // Add fully qualified path for dependency purposes
1777 // if we're collecting them
1778 if (fullResPaths
!= NULL
) {
1779 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1788 * Stash away the files and recursively descend into subdirectories.
1790 const size_t N
= fileNames
.size();
1792 for (i
= 0; i
< N
; i
++) {
1793 String8
pathName(srcDir
);
1796 pathName
.appendPath(fileNames
[i
].string());
1797 type
= getFileType(pathName
.string());
1798 if (type
== kFileTypeDirectory
) {
1800 bool notAdded
= false;
1801 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1802 subdir
= mDirs
.valueFor(fileNames
[i
]);
1804 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1807 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1808 resType
, fullResPaths
);
1809 if (res
< NO_ERROR
) {
1812 if (res
> 0 && notAdded
) {
1813 mDirs
.add(fileNames
[i
], subdir
);
1816 } else if (type
== kFileTypeRegular
) {
1817 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1818 status_t err
= addLeafFile(fileNames
[i
], file
);
1819 if (err
!= NO_ERROR
) {
1826 if (bundle
->getVerbose())
1827 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1834 status_t
AaptDir::validate() const
1836 const size_t NF
= mFiles
.size();
1837 const size_t ND
= mDirs
.size();
1839 for (i
= 0; i
< NF
; i
++) {
1840 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1841 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1842 "Invalid filename. Unable to add.");
1843 return UNKNOWN_ERROR
;
1847 for (j
= i
+1; j
< NF
; j
++) {
1848 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1849 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1850 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1851 "File is case-insensitive equivalent to: %s",
1852 mFiles
.valueAt(j
)->getPrintableSource().string());
1853 return UNKNOWN_ERROR
;
1856 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1857 // (this is mostly caught by the "marked" stuff, below)
1860 for (j
= 0; j
< ND
; j
++) {
1861 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1862 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1863 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1864 "File conflicts with dir from: %s",
1865 mDirs
.valueAt(j
)->getPrintableSource().string());
1866 return UNKNOWN_ERROR
;
1871 for (i
= 0; i
< ND
; i
++) {
1872 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1873 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1874 "Invalid directory name, unable to add.");
1875 return UNKNOWN_ERROR
;
1879 for (j
= i
+1; j
< ND
; j
++) {
1880 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1881 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1882 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1883 "Directory is case-insensitive equivalent to: %s",
1884 mDirs
.valueAt(j
)->getPrintableSource().string());
1885 return UNKNOWN_ERROR
;
1889 status_t err
= mDirs
.valueAt(i
)->validate();
1890 if (err
!= NO_ERROR
) {
1898 void AaptDir::print(const String8
& prefix
) const
1900 const size_t ND
=getDirs().size();
1902 for (i
=0; i
<ND
; i
++) {
1903 getDirs().valueAt(i
)->print(prefix
);
1906 const size_t NF
=getFiles().size();
1907 for (i
=0; i
<NF
; i
++) {
1908 getFiles().valueAt(i
)->print(prefix
);
1912 String8
AaptDir::getPrintableSource() const
1914 if (mFiles
.size() > 0) {
1915 // Arbitrarily pull the first file out of the list as the source dir.
1916 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1918 if (mDirs
.size() > 0) {
1919 // Or arbitrarily pull the first dir out of the list as the source dir.
1920 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1923 // Should never hit this case, but to be safe...
1928 // =========================================================================
1929 // =========================================================================
1930 // =========================================================================
1932 status_t
AaptSymbols::applyJavaSymbols(const sp
<AaptSymbols
>& javaSymbols
)
1934 status_t err
= NO_ERROR
;
1935 size_t N
= javaSymbols
->mSymbols
.size();
1936 for (size_t i
=0; i
<N
; i
++) {
1937 const String8
& name
= javaSymbols
->mSymbols
.keyAt(i
);
1938 const AaptSymbolEntry
& entry
= javaSymbols
->mSymbols
.valueAt(i
);
1939 ssize_t pos
= mSymbols
.indexOfKey(name
);
1941 entry
.sourcePos
.error("Symbol '%s' declared with <java-symbol> not defined\n", name
.string());
1942 err
= UNKNOWN_ERROR
;
1945 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1946 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1947 mSymbols
.editValueAt(pos
).isJavaSymbol
= entry
.isJavaSymbol
;
1950 N
= javaSymbols
->mNestedSymbols
.size();
1951 for (size_t i
=0; i
<N
; i
++) {
1952 const String8
& name
= javaSymbols
->mNestedSymbols
.keyAt(i
);
1953 const sp
<AaptSymbols
>& symbols
= javaSymbols
->mNestedSymbols
.valueAt(i
);
1954 ssize_t pos
= mNestedSymbols
.indexOfKey(name
);
1957 pos
.error("Java symbol dir %s not defined\n", name
.string());
1958 err
= UNKNOWN_ERROR
;
1961 //printf("**** applying java symbols in dir %s\n", name.string());
1962 status_t myerr
= mNestedSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
1963 if (myerr
!= NO_ERROR
) {
1971 // =========================================================================
1972 // =========================================================================
1973 // =========================================================================
1975 AaptAssets::AaptAssets()
1976 : AaptDir(String8(), String8()),
1977 mChanged(false), mHaveIncludedAssets(false), mRes(NULL
)
1981 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const {
1984 return mGroupEntries
;
1987 status_t
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1990 return AaptDir::addFile(name
, file
);
1993 sp
<AaptFile
> AaptAssets::addFile(
1994 const String8
& filePath
, const AaptGroupEntry
& entry
,
1995 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1996 const String8
& resType
)
1998 sp
<AaptDir
> dir
= this;
1999 sp
<AaptGroup
> group
;
2001 String8 root
, remain(filePath
), partialPath
;
2002 while (remain
.length() > 0) {
2003 root
= remain
.walkPath(&remain
);
2004 partialPath
.appendPath(root
);
2006 const String8
rootStr(root
);
2008 if (remain
.length() == 0) {
2009 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
2011 group
= dir
->getFiles().valueAt(i
);
2013 group
= new AaptGroup(rootStr
, filePath
);
2014 status_t res
= dir
->addFile(rootStr
, group
);
2015 if (res
!= NO_ERROR
) {
2019 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
2020 status_t res
= group
->addFile(file
);
2021 if (res
!= NO_ERROR
) {
2027 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
2029 dir
= dir
->getDirs().valueAt(i
);
2031 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
2032 status_t res
= dir
->addDir(rootStr
, subdir
);
2033 if (res
!= NO_ERROR
) {
2041 mGroupEntries
.add(entry
);
2042 if (outGroup
) *outGroup
= group
;
2046 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
2047 const sp
<AaptFile
>& file
, const String8
& resType
)
2049 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
2050 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
2051 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
2052 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
2055 subdir
->addFile(leafName
, grr
);
2059 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
2064 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
2065 const size_t dirCount
=resDirs
.size();
2066 sp
<AaptAssets
> current
= this;
2068 const int N
= bundle
->getFileSpecCount();
2071 * If a package manifest was specified, include that first.
2073 if (bundle
->getAndroidManifestFile() != NULL
) {
2074 // place at root of zip.
2075 String8
srcFile(bundle
->getAndroidManifestFile());
2076 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
2082 * If a directory of custom assets was supplied, slurp 'em up.
2084 if (bundle
->getAssetSourceDir()) {
2085 const char* assetDir
= bundle
->getAssetSourceDir();
2087 FileType type
= getFileType(assetDir
);
2088 if (type
== kFileTypeNonexistent
) {
2089 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
2090 return UNKNOWN_ERROR
;
2092 if (type
!= kFileTypeDirectory
) {
2093 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2094 return UNKNOWN_ERROR
;
2097 String8
assetRoot(assetDir
);
2098 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
2099 AaptGroupEntry group
;
2100 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
2101 String8(), mFullAssetPaths
);
2107 mGroupEntries
.add(group
);
2109 totalCount
+= count
;
2111 if (bundle
->getVerbose())
2112 printf("Found %d custom asset file%s in %s\n",
2113 count
, (count
==1) ? "" : "s", assetDir
);
2117 * If a directory of resource-specific assets was supplied, slurp 'em up.
2119 for (size_t i
=0; i
<dirCount
; i
++) {
2120 const char *res
= resDirs
[i
];
2122 type
= getFileType(res
);
2123 if (type
== kFileTypeNonexistent
) {
2124 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
2125 return UNKNOWN_ERROR
;
2127 if (type
== kFileTypeDirectory
) {
2129 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
2130 current
->setOverlay(nextOverlay
);
2131 current
= nextOverlay
;
2132 current
->setFullResPaths(mFullResPaths
);
2134 count
= current
->slurpResourceTree(bundle
, String8(res
));
2140 totalCount
+= count
;
2143 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
2144 return UNKNOWN_ERROR
;
2150 * Now do any additional raw files.
2152 for (int arg
=0; arg
<N
; arg
++) {
2153 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
2155 FileType type
= getFileType(assetDir
);
2156 if (type
== kFileTypeNonexistent
) {
2157 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
2158 return UNKNOWN_ERROR
;
2160 if (type
!= kFileTypeDirectory
) {
2161 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2162 return UNKNOWN_ERROR
;
2165 String8
assetRoot(assetDir
);
2167 if (bundle
->getVerbose())
2168 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
2171 * Do a recursive traversal of subdir tree. We don't make any
2172 * guarantees about ordering, so we're okay with an inorder search
2173 * using whatever order the OS happens to hand back to us.
2175 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
2177 /* failure; report error and remove archive */
2181 totalCount
+= count
;
2183 if (bundle
->getVerbose())
2184 printf("Found %d asset file%s in %s\n",
2185 count
, (count
==1) ? "" : "s", assetDir
);
2189 if (count
!= NO_ERROR
) {
2194 count
= filter(bundle
);
2195 if (count
!= NO_ERROR
) {
2204 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
2205 const AaptGroupEntry
& kind
,
2206 const String8
& resType
,
2207 sp
<FilePathStore
>& fullResPaths
)
2209 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
2211 mGroupEntries
.add(kind
);
2217 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
2221 DIR* dir
= opendir(srcDir
.string());
2223 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
2224 return UNKNOWN_ERROR
;
2230 * Run through the directory, looking for dirs that match the
2234 struct dirent
* entry
= readdir(dir
);
2235 if (entry
== NULL
) {
2239 if (isHidden(srcDir
.string(), entry
->d_name
)) {
2243 String8
subdirName(srcDir
);
2244 subdirName
.appendPath(entry
->d_name
);
2246 AaptGroupEntry group
;
2248 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
2250 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2256 if (bundle
->getMaxResVersion() != NULL
&& group
.getVersionString().length() != 0) {
2257 int maxResInt
= atoi(bundle
->getMaxResVersion());
2258 const char *verString
= group
.getVersionString().string();
2259 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2260 if (dirVersionInt
> maxResInt
) {
2261 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2266 FileType type
= getFileType(subdirName
.string());
2268 if (type
== kFileTypeDirectory
) {
2269 sp
<AaptDir
> dir
= makeDir(resType
);
2270 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2271 resType
, mFullResPaths
);
2277 mGroupEntries
.add(group
);
2281 // Only add this directory if we don't already have a resource dir
2282 // for the current type. This ensures that we only add the dir once
2284 sp
<AaptDir
> rdir
= resDir(resType
);
2289 if (bundle
->getVerbose()) {
2290 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2306 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2309 SortedVector
<AaptGroupEntry
> entries
;
2311 ZipFile
* zip
= new ZipFile
;
2312 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2313 if (err
!= NO_ERROR
) {
2314 fprintf(stderr
, "error opening zip file %s\n", filename
);
2320 const int N
= zip
->getNumEntries();
2321 for (int i
=0; i
<N
; i
++) {
2322 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2323 if (entry
->getDeleted()) {
2327 String8
entryName(entry
->getFileName());
2329 String8 dirName
= entryName
.getPathDir();
2330 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2333 AaptGroupEntry kind
;
2336 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2337 // these are the resources, pull their type out of the directory name
2338 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2340 // these are untyped and don't have an AaptGroupEntry
2342 if (entries
.indexOf(kind
) < 0) {
2344 mGroupEntries
.add(kind
);
2347 // use the one from the zip file if they both exist.
2348 dir
->removeFile(entryName
.getPathLeaf());
2350 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2351 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2352 if (err
!= NO_ERROR
) {
2353 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2357 file
->setCompressionMethod(entry
->getCompressionMethod());
2360 if (entryName
== "AndroidManifest.xml") {
2361 printf("AndroidManifest.xml\n");
2363 printf("\n\nfile: %s\n", entryName
.string());
2366 size_t len
= entry
->getUncompressedLen();
2367 void* data
= zip
->uncompress(entry
);
2368 void* buf
= file
->editData(len
);
2369 memcpy(buf
, data
, len
);
2373 const unsigned char* p
= (unsigned char*)data
;
2374 const unsigned char* end
= p
+len
;
2376 for (int i
=0; i
<32 && p
< end
; i
++) {
2377 printf("0x%03x ", i
*0x10 + OFF
);
2378 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2379 printf(" %02x", *p
);
2396 status_t
AaptAssets::filter(Bundle
* bundle
)
2398 ResourceFilter reqFilter
;
2399 status_t err
= reqFilter
.parse(bundle
->getConfigurations());
2400 if (err
!= NO_ERROR
) {
2404 ResourceFilter prefFilter
;
2405 err
= prefFilter
.parse(bundle
->getPreferredConfigurations());
2406 if (err
!= NO_ERROR
) {
2410 if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) {
2414 if (bundle
->getVerbose()) {
2415 if (!reqFilter
.isEmpty()) {
2416 printf("Applying required filter: %s\n",
2417 bundle
->getConfigurations());
2419 if (!prefFilter
.isEmpty()) {
2420 printf("Applying preferred filter: %s\n",
2421 bundle
->getPreferredConfigurations());
2425 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2426 const size_t ND
= resdirs
.size();
2427 for (size_t i
=0; i
<ND
; i
++) {
2428 const sp
<AaptDir
>& dir
= resdirs
.itemAt(i
);
2429 if (dir
->getLeaf() == kValuesDir
) {
2430 // The "value" dir is special since a single file defines
2431 // multiple resources, so we can not do filtering on the
2432 // files themselves.
2435 if (dir
->getLeaf() == kMipmapDir
) {
2436 // We also skip the "mipmap" directory, since the point of this
2437 // is to include all densities without stripping. If you put
2438 // other configurations in here as well they won't be stripped
2439 // either... So don't do that. Seriously. What is wrong with you?
2443 const size_t NG
= dir
->getFiles().size();
2444 for (size_t j
=0; j
<NG
; j
++) {
2445 sp
<AaptGroup
> grp
= dir
->getFiles().valueAt(j
);
2447 // First remove any configurations we know we don't need.
2448 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2449 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2450 if (k
== 0 && grp
->getFiles().size() == 1) {
2451 // If this is the only file left, we need to keep it.
2452 // Otherwise the resource IDs we are using will be inconsistent
2453 // with what we get when not stripping. Sucky, but at least
2454 // for now we can rely on the back-end doing another filtering
2455 // pass to take this out and leave us with this resource name
2456 // containing no entries.
2459 if (file
->getPath().getPathExtension() == ".xml") {
2460 // We can't remove .xml files at this point, because when
2461 // we parse them they may add identifier resources, so
2462 // removing them can cause our resource identifiers to
2463 // become inconsistent.
2466 const ResTable_config
& config(file
->getGroupEntry().toParams());
2467 if (!reqFilter
.match(config
)) {
2468 if (bundle
->getVerbose()) {
2469 printf("Pruning unneeded resource: %s\n",
2470 file
->getPrintableSource().string());
2477 // Quick check: no preferred filters, nothing more to do.
2478 if (prefFilter
.isEmpty()) {
2482 // Now deal with preferred configurations.
2483 for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) {
2484 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2485 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2486 if (k
== 0 && grp
->getFiles().size() == 1) {
2487 // If this is the only file left, we need to keep it.
2488 // Otherwise the resource IDs we are using will be inconsistent
2489 // with what we get when not stripping. Sucky, but at least
2490 // for now we can rely on the back-end doing another filtering
2491 // pass to take this out and leave us with this resource name
2492 // containing no entries.
2495 if (file
->getPath().getPathExtension() == ".xml") {
2496 // We can't remove .xml files at this point, because when
2497 // we parse them they may add identifier resources, so
2498 // removing them can cause our resource identifiers to
2499 // become inconsistent.
2502 const ResTable_config
& config(file
->getGroupEntry().toParams());
2503 if (!prefFilter
.match(axis
, config
)) {
2504 // This is a resource we would prefer not to have. Check
2505 // to see if have a similar variation that we would like
2506 // to have and, if so, we can drop it.
2507 for (size_t m
=0; m
<grp
->getFiles().size(); m
++) {
2508 if (m
== k
) continue;
2509 sp
<AaptFile
> mfile
= grp
->getFiles().valueAt(m
);
2510 const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams());
2511 if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) {
2512 if (prefFilter
.match(axis
, mconfig
)) {
2513 if (bundle
->getVerbose()) {
2514 printf("Pruning unneeded resource: %s\n",
2515 file
->getPrintableSource().string());
2532 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2534 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2536 sym
= new AaptSymbols();
2537 mSymbols
.add(name
, sym
);
2542 sp
<AaptSymbols
> AaptAssets::getJavaSymbolsFor(const String8
& name
)
2544 sp
<AaptSymbols
> sym
= mJavaSymbols
.valueFor(name
);
2546 sym
= new AaptSymbols();
2547 mJavaSymbols
.add(name
, sym
);
2552 status_t
AaptAssets::applyJavaSymbols()
2554 size_t N
= mJavaSymbols
.size();
2555 for (size_t i
=0; i
<N
; i
++) {
2556 const String8
& name
= mJavaSymbols
.keyAt(i
);
2557 const sp
<AaptSymbols
>& symbols
= mJavaSymbols
.valueAt(i
);
2558 ssize_t pos
= mSymbols
.indexOfKey(name
);
2561 pos
.error("Java symbol dir %s not defined\n", name
.string());
2562 return UNKNOWN_ERROR
;
2564 //printf("**** applying java symbols in dir %s\n", name.string());
2565 status_t err
= mSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
2566 if (err
!= NO_ERROR
) {
2574 bool AaptAssets::isJavaSymbol(const AaptSymbolEntry
& sym
, bool includePrivate
) const {
2575 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2576 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2577 // sym.isJavaSymbol ? 1 : 0);
2578 if (!mHavePrivateSymbols
) return true;
2579 if (sym
.isPublic
) return true;
2580 if (includePrivate
&& sym
.isJavaSymbol
) return true;
2584 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2586 if (!mHaveIncludedAssets
) {
2587 // Add in all includes.
2588 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2589 const size_t N
=incl
.size();
2590 for (size_t i
=0; i
<N
; i
++) {
2591 if (bundle
->getVerbose())
2592 printf("Including resources from package: %s\n", incl
[i
]);
2593 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2594 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2596 return UNKNOWN_ERROR
;
2599 mHaveIncludedAssets
= true;
2605 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2607 const ResTable
& res
= getIncludedResources();
2609 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2612 const ResTable
& AaptAssets::getIncludedResources() const
2614 return mIncludedAssets
.getResources(false);
2617 void AaptAssets::print(const String8
& prefix
) const
2619 String8
innerPrefix(prefix
);
2620 innerPrefix
.append(" ");
2621 String8
innerInnerPrefix(innerPrefix
);
2622 innerInnerPrefix
.append(" ");
2623 printf("%sConfigurations:\n", prefix
.string());
2624 const size_t N
=mGroupEntries
.size();
2625 for (size_t i
=0; i
<N
; i
++) {
2626 String8 cname
= mGroupEntries
.itemAt(i
).toDirName(String8());
2627 printf("%s %s\n", prefix
.string(),
2628 cname
!= "" ? cname
.string() : "(default)");
2631 printf("\n%sFiles:\n", prefix
.string());
2632 AaptDir::print(innerPrefix
);
2634 printf("\n%sResource Dirs:\n", prefix
.string());
2635 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2636 const size_t NR
= resdirs
.size();
2637 for (size_t i
=0; i
<NR
; i
++) {
2638 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2639 printf("%s Type %s\n", prefix
.string(), d
->getLeaf().string());
2640 d
->print(innerInnerPrefix
);
2644 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const
2646 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2647 const size_t N
= resdirs
.size();
2648 for (size_t i
=0; i
<N
; i
++) {
2649 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2650 if (d
->getLeaf() == name
) {
2658 valid_symbol_name(const String8
& symbol
)
2660 static char const * const KEYWORDS
[] = {
2661 "abstract", "assert", "boolean", "break",
2662 "byte", "case", "catch", "char", "class", "const", "continue",
2663 "default", "do", "double", "else", "enum", "extends", "final",
2664 "finally", "float", "for", "goto", "if", "implements", "import",
2665 "instanceof", "int", "interface", "long", "native", "new", "package",
2666 "private", "protected", "public", "return", "short", "static",
2667 "strictfp", "super", "switch", "synchronized", "this", "throw",
2668 "throws", "transient", "try", "void", "volatile", "while",
2669 "true", "false", "null",
2672 const char*const* k
= KEYWORDS
;
2673 const char*const s
= symbol
.string();
2675 if (0 == strcmp(s
, *k
)) {