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:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~";
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] == '*') {
126 ignore
= strncasecmp(token
, path
+ plen
- n
, n
) == 0;
128 } else if (n
> 1 && token
[n
- 1] == '*') {
130 ignore
= strncasecmp(token
, path
, n
- 1) == 0;
132 ignore
= strcasecmp(token
, path
) == 0;
136 if (ignore
&& chatty
) {
137 fprintf(stderr
, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
138 type
== kFileTypeDirectory
? "dir" : "file",
140 matchedPattern
? matchedPattern
: "");
147 // =========================================================================
148 // =========================================================================
149 // =========================================================================
152 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
)
154 ResTable_config config
;
157 if (getMccName(part
.string(), &config
)) {
164 if (getMncName(part
.string(), &config
)) {
171 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
172 *axis
= AXIS_LANGUAGE
;
173 *value
= part
[1] << 8 | part
[0];
177 // locale - language_REGION
178 if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1])
179 && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) {
180 *axis
= AXIS_LANGUAGE
;
181 *value
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]);
185 // smallest screen dp width
186 if (getSmallestScreenWidthDpName(part
.string(), &config
)) {
187 *axis
= AXIS_SMALLESTSCREENWIDTHDP
;
188 *value
= config
.smallestScreenWidthDp
;
193 if (getScreenWidthDpName(part
.string(), &config
)) {
194 *axis
= AXIS_SCREENWIDTHDP
;
195 *value
= config
.screenWidthDp
;
200 if (getScreenHeightDpName(part
.string(), &config
)) {
201 *axis
= AXIS_SCREENHEIGHTDP
;
202 *value
= config
.screenHeightDp
;
206 // screen layout size
207 if (getScreenLayoutSizeName(part
.string(), &config
)) {
208 *axis
= AXIS_SCREENLAYOUTSIZE
;
209 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
213 // screen layout long
214 if (getScreenLayoutLongName(part
.string(), &config
)) {
215 *axis
= AXIS_SCREENLAYOUTLONG
;
216 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
221 if (getOrientationName(part
.string(), &config
)) {
222 *axis
= AXIS_ORIENTATION
;
223 *value
= config
.orientation
;
228 if (getUiModeTypeName(part
.string(), &config
)) {
229 *axis
= AXIS_UIMODETYPE
;
230 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
235 if (getUiModeNightName(part
.string(), &config
)) {
236 *axis
= AXIS_UIMODENIGHT
;
237 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
242 if (getDensityName(part
.string(), &config
)) {
243 *axis
= AXIS_DENSITY
;
244 *value
= config
.density
;
249 if (getTouchscreenName(part
.string(), &config
)) {
250 *axis
= AXIS_TOUCHSCREEN
;
251 *value
= config
.touchscreen
;
256 if (getKeysHiddenName(part
.string(), &config
)) {
257 *axis
= AXIS_KEYSHIDDEN
;
258 *value
= config
.inputFlags
;
263 if (getKeyboardName(part
.string(), &config
)) {
264 *axis
= AXIS_KEYBOARD
;
265 *value
= config
.keyboard
;
270 if (getNavHiddenName(part
.string(), &config
)) {
271 *axis
= AXIS_NAVHIDDEN
;
272 *value
= config
.inputFlags
;
277 if (getNavigationName(part
.string(), &config
)) {
278 *axis
= AXIS_NAVIGATION
;
279 *value
= config
.navigation
;
284 if (getScreenSizeName(part
.string(), &config
)) {
285 *axis
= AXIS_SCREENSIZE
;
286 *value
= config
.screenSize
;
291 if (getVersionName(part
.string(), &config
)) {
292 *axis
= AXIS_VERSION
;
293 *value
= config
.version
;
301 AaptGroupEntry::getConfigValueForAxis(const ResTable_config
& config
, int axis
)
309 return (((uint32_t)config
.country
[1]) << 24) | (((uint32_t)config
.country
[0]) << 16)
310 | (((uint32_t)config
.language
[1]) << 8) | (config
.language
[0]);
311 case AXIS_SCREENLAYOUTSIZE
:
312 return config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
;
313 case AXIS_ORIENTATION
:
314 return config
.orientation
;
315 case AXIS_UIMODETYPE
:
316 return (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
317 case AXIS_UIMODENIGHT
:
318 return (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
320 return config
.density
;
321 case AXIS_TOUCHSCREEN
:
322 return config
.touchscreen
;
323 case AXIS_KEYSHIDDEN
:
324 return config
.inputFlags
;
326 return config
.keyboard
;
327 case AXIS_NAVIGATION
:
328 return config
.navigation
;
329 case AXIS_SCREENSIZE
:
330 return config
.screenSize
;
331 case AXIS_SMALLESTSCREENWIDTHDP
:
332 return config
.smallestScreenWidthDp
;
333 case AXIS_SCREENWIDTHDP
:
334 return config
.screenWidthDp
;
335 case AXIS_SCREENHEIGHTDP
:
336 return config
.screenHeightDp
;
338 return config
.version
;
344 AaptGroupEntry::configSameExcept(const ResTable_config
& config
,
345 const ResTable_config
& otherConfig
, int axis
)
347 for (int i
=AXIS_START
; i
<=AXIS_END
; i
++) {
351 if (getConfigValueForAxis(config
, i
) != getConfigValueForAxis(otherConfig
, i
)) {
359 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
361 mParamsChanged
= true;
363 Vector
<String8
> parts
;
365 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
366 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
;
367 String8 uiModeType
, uiModeNight
, smallestwidthdp
, widthdp
, heightdp
;
371 while (NULL
!= (q
= strchr(p
, '-'))) {
375 //printf("part: %s\n", parts[parts.size()-1].string());
381 //printf("part: %s\n", parts[parts.size()-1].string());
383 const int N
= parts
.size();
385 String8 part
= parts
[index
];
388 if (!isValidResourceType(part
)) {
400 if (getMccName(part
.string())) {
409 //printf("not mcc: %s\n", part.string());
413 if (getMncName(part
.string())) {
422 //printf("not mcc: %s\n", part.string());
426 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
435 //printf("not language: %s\n", part.string());
440 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
443 loc
+= part
.string() + 1;
451 //printf("not region: %s\n", part.string());
454 if (getSmallestScreenWidthDpName(part
.string())) {
455 smallestwidthdp
= part
;
463 //printf("not smallest screen width dp: %s\n", part.string());
466 if (getScreenWidthDpName(part
.string())) {
475 //printf("not screen width dp: %s\n", part.string());
478 if (getScreenHeightDpName(part
.string())) {
487 //printf("not screen height dp: %s\n", part.string());
490 if (getScreenLayoutSizeName(part
.string())) {
499 //printf("not screen layout size: %s\n", part.string());
502 if (getScreenLayoutLongName(part
.string())) {
511 //printf("not screen layout long: %s\n", part.string());
515 if (getOrientationName(part
.string())) {
524 //printf("not orientation: %s\n", part.string());
528 if (getUiModeTypeName(part
.string())) {
537 //printf("not ui mode type: %s\n", part.string());
541 if (getUiModeNightName(part
.string())) {
550 //printf("not ui mode night: %s\n", part.string());
554 if (getDensityName(part
.string())) {
563 //printf("not density: %s\n", part.string());
567 if (getTouchscreenName(part
.string())) {
576 //printf("not touchscreen: %s\n", part.string());
580 if (getKeysHiddenName(part
.string())) {
589 //printf("not keysHidden: %s\n", part.string());
593 if (getKeyboardName(part
.string())) {
602 //printf("not keyboard: %s\n", part.string());
606 if (getNavHiddenName(part
.string())) {
615 //printf("not navHidden: %s\n", part.string());
618 if (getNavigationName(part
.string())) {
627 //printf("not navigation: %s\n", part.string());
630 if (getScreenSizeName(part
.string())) {
639 //printf("not screen size: %s\n", part.string());
642 if (getVersionName(part
.string())) {
651 //printf("not version: %s\n", part.string());
654 // if there are extra parts, it doesn't match
661 this->screenLayoutSize
= layoutsize
;
662 this->screenLayoutLong
= layoutlong
;
663 this->smallestScreenWidthDp
= smallestwidthdp
;
664 this->screenWidthDp
= widthdp
;
665 this->screenHeightDp
= heightdp
;
666 this->orientation
= orient
;
667 this->uiModeType
= uiModeType
;
668 this->uiModeNight
= uiModeNight
;
670 this->touchscreen
= touch
;
671 this->keysHidden
= keysHidden
;
672 this->keyboard
= key
;
673 this->navHidden
= navHidden
;
674 this->navigation
= nav
;
675 this->screenSize
= size
;
676 this->version
= vers
;
678 // what is this anyway?
685 AaptGroupEntry::toString() const
687 String8 s
= this->mcc
;
693 s
+= smallestScreenWidthDp
;
699 s
+= screenLayoutSize
;
701 s
+= screenLayoutLong
;
703 s
+= this->orientation
;
728 AaptGroupEntry::toDirName(const String8
& resType
) const
731 if (this->mcc
!= "") {
732 if (s
.length() > 0) {
737 if (this->mnc
!= "") {
738 if (s
.length() > 0) {
743 if (this->locale
!= "") {
744 if (s
.length() > 0) {
749 if (this->smallestScreenWidthDp
!= "") {
750 if (s
.length() > 0) {
753 s
+= smallestScreenWidthDp
;
755 if (this->screenWidthDp
!= "") {
756 if (s
.length() > 0) {
761 if (this->screenHeightDp
!= "") {
762 if (s
.length() > 0) {
767 if (this->screenLayoutSize
!= "") {
768 if (s
.length() > 0) {
771 s
+= screenLayoutSize
;
773 if (this->screenLayoutLong
!= "") {
774 if (s
.length() > 0) {
777 s
+= screenLayoutLong
;
779 if (this->orientation
!= "") {
780 if (s
.length() > 0) {
785 if (this->uiModeType
!= "") {
786 if (s
.length() > 0) {
791 if (this->uiModeNight
!= "") {
792 if (s
.length() > 0) {
797 if (this->density
!= "") {
798 if (s
.length() > 0) {
803 if (this->touchscreen
!= "") {
804 if (s
.length() > 0) {
809 if (this->keysHidden
!= "") {
810 if (s
.length() > 0) {
815 if (this->keyboard
!= "") {
816 if (s
.length() > 0) {
821 if (this->navHidden
!= "") {
822 if (s
.length() > 0) {
827 if (this->navigation
!= "") {
828 if (s
.length() > 0) {
833 if (this->screenSize
!= "") {
834 if (s
.length() > 0) {
839 if (this->version
!= "") {
840 if (s
.length() > 0) {
849 bool AaptGroupEntry::getMccName(const char* name
,
850 ResTable_config
* out
)
852 if (strcmp(name
, kWildcardName
) == 0) {
853 if (out
) out
->mcc
= 0;
856 const char* c
= name
;
857 if (tolower(*c
) != 'm') return false;
859 if (tolower(*c
) != 'c') return false;
861 if (tolower(*c
) != 'c') return false;
866 while (*c
>= '0' && *c
<= '9') {
869 if (*c
!= 0) return false;
870 if (c
-val
!= 3) return false;
874 if (out
) out
->mcc
= d
;
881 bool AaptGroupEntry::getMncName(const char* name
,
882 ResTable_config
* out
)
884 if (strcmp(name
, kWildcardName
) == 0) {
885 if (out
) out
->mcc
= 0;
888 const char* c
= name
;
889 if (tolower(*c
) != 'm') return false;
891 if (tolower(*c
) != 'n') return false;
893 if (tolower(*c
) != 'c') return false;
898 while (*c
>= '0' && *c
<= '9') {
901 if (*c
!= 0) return false;
902 if (c
-val
== 0 || c
-val
> 3) return false;
905 out
->mnc
= atoi(val
);
912 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
915 * TODO: Should insist that the first two letters are lower case, and the
916 * second two are upper.
918 bool AaptGroupEntry::getLocaleName(const char* fileName
,
919 ResTable_config
* out
)
921 if (strcmp(fileName
, kWildcardName
) == 0
922 || strcmp(fileName
, kDefaultLocale
) == 0) {
924 out
->language
[0] = 0;
925 out
->language
[1] = 0;
932 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
934 out
->language
[0] = fileName
[0];
935 out
->language
[1] = fileName
[1];
942 if (strlen(fileName
) == 5 &&
943 isalpha(fileName
[0]) &&
944 isalpha(fileName
[1]) &&
945 fileName
[2] == '-' &&
946 isalpha(fileName
[3]) &&
947 isalpha(fileName
[4])) {
949 out
->language
[0] = fileName
[0];
950 out
->language
[1] = fileName
[1];
951 out
->country
[0] = fileName
[3];
952 out
->country
[1] = fileName
[4];
960 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
961 ResTable_config
* out
)
963 if (strcmp(name
, kWildcardName
) == 0) {
964 if (out
) out
->screenLayout
=
965 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
966 | ResTable_config::SCREENSIZE_ANY
;
968 } else if (strcmp(name
, "small") == 0) {
969 if (out
) out
->screenLayout
=
970 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
971 | ResTable_config::SCREENSIZE_SMALL
;
973 } else if (strcmp(name
, "normal") == 0) {
974 if (out
) out
->screenLayout
=
975 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
976 | ResTable_config::SCREENSIZE_NORMAL
;
978 } else if (strcmp(name
, "large") == 0) {
979 if (out
) out
->screenLayout
=
980 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
981 | ResTable_config::SCREENSIZE_LARGE
;
983 } else if (strcmp(name
, "xlarge") == 0) {
984 if (out
) out
->screenLayout
=
985 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
986 | ResTable_config::SCREENSIZE_XLARGE
;
993 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
994 ResTable_config
* out
)
996 if (strcmp(name
, kWildcardName
) == 0) {
997 if (out
) out
->screenLayout
=
998 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
999 | ResTable_config::SCREENLONG_ANY
;
1001 } else if (strcmp(name
, "long") == 0) {
1002 if (out
) out
->screenLayout
=
1003 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1004 | ResTable_config::SCREENLONG_YES
;
1006 } else if (strcmp(name
, "notlong") == 0) {
1007 if (out
) out
->screenLayout
=
1008 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1009 | ResTable_config::SCREENLONG_NO
;
1016 bool AaptGroupEntry::getOrientationName(const char* name
,
1017 ResTable_config
* out
)
1019 if (strcmp(name
, kWildcardName
) == 0) {
1020 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
1022 } else if (strcmp(name
, "port") == 0) {
1023 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
1025 } else if (strcmp(name
, "land") == 0) {
1026 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
1028 } else if (strcmp(name
, "square") == 0) {
1029 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
1036 bool AaptGroupEntry::getUiModeTypeName(const char* name
,
1037 ResTable_config
* out
)
1039 if (strcmp(name
, kWildcardName
) == 0) {
1040 if (out
) out
->uiMode
=
1041 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1042 | ResTable_config::UI_MODE_TYPE_ANY
;
1044 } else if (strcmp(name
, "desk") == 0) {
1045 if (out
) out
->uiMode
=
1046 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1047 | ResTable_config::UI_MODE_TYPE_DESK
;
1049 } else if (strcmp(name
, "car") == 0) {
1050 if (out
) out
->uiMode
=
1051 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1052 | ResTable_config::UI_MODE_TYPE_CAR
;
1054 } else if (strcmp(name
, "television") == 0) {
1055 if (out
) out
->uiMode
=
1056 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1057 | ResTable_config::UI_MODE_TYPE_TELEVISION
;
1059 } else if (strcmp(name
, "appliance") == 0) {
1060 if (out
) out
->uiMode
=
1061 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1062 | ResTable_config::UI_MODE_TYPE_APPLIANCE
;
1069 bool AaptGroupEntry::getUiModeNightName(const char* name
,
1070 ResTable_config
* out
)
1072 if (strcmp(name
, kWildcardName
) == 0) {
1073 if (out
) out
->uiMode
=
1074 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1075 | ResTable_config::UI_MODE_NIGHT_ANY
;
1077 } else if (strcmp(name
, "night") == 0) {
1078 if (out
) out
->uiMode
=
1079 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1080 | ResTable_config::UI_MODE_NIGHT_YES
;
1082 } else if (strcmp(name
, "notnight") == 0) {
1083 if (out
) out
->uiMode
=
1084 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1085 | ResTable_config::UI_MODE_NIGHT_NO
;
1092 bool AaptGroupEntry::getDensityName(const char* name
,
1093 ResTable_config
* out
)
1095 if (strcmp(name
, kWildcardName
) == 0) {
1096 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
1100 if (strcmp(name
, "nodpi") == 0) {
1101 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
1105 if (strcmp(name
, "ldpi") == 0) {
1106 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
1110 if (strcmp(name
, "mdpi") == 0) {
1111 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
1115 if (strcmp(name
, "tvdpi") == 0) {
1116 if (out
) out
->density
= ResTable_config::DENSITY_TV
;
1120 if (strcmp(name
, "hdpi") == 0) {
1121 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
1125 if (strcmp(name
, "xhdpi") == 0) {
1126 if (out
) out
->density
= ResTable_config::DENSITY_XHIGH
;
1130 if (strcmp(name
, "xxhdpi") == 0) {
1131 if (out
) out
->density
= ResTable_config::DENSITY_XXHIGH
;
1135 char* c
= (char*)name
;
1136 while (*c
>= '0' && *c
<= '9') {
1140 // check that we have 'dpi' after the last digit.
1141 if (toupper(c
[0]) != 'D' ||
1142 toupper(c
[1]) != 'P' ||
1143 toupper(c
[2]) != 'I' ||
1148 // temporarily replace the first letter with \0 to
1157 if (out
) out
->density
= d
;
1164 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1165 ResTable_config
* out
)
1167 if (strcmp(name
, kWildcardName
) == 0) {
1168 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1170 } else if (strcmp(name
, "notouch") == 0) {
1171 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1173 } else if (strcmp(name
, "stylus") == 0) {
1174 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1176 } else if (strcmp(name
, "finger") == 0) {
1177 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1184 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1185 ResTable_config
* out
)
1189 if (strcmp(name
, kWildcardName
) == 0) {
1190 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1191 value
= ResTable_config::KEYSHIDDEN_ANY
;
1192 } else if (strcmp(name
, "keysexposed") == 0) {
1193 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1194 value
= ResTable_config::KEYSHIDDEN_NO
;
1195 } else if (strcmp(name
, "keyshidden") == 0) {
1196 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1197 value
= ResTable_config::KEYSHIDDEN_YES
;
1198 } else if (strcmp(name
, "keyssoft") == 0) {
1199 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1200 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1204 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1211 bool AaptGroupEntry::getKeyboardName(const char* name
,
1212 ResTable_config
* out
)
1214 if (strcmp(name
, kWildcardName
) == 0) {
1215 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1217 } else if (strcmp(name
, "nokeys") == 0) {
1218 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1220 } else if (strcmp(name
, "qwerty") == 0) {
1221 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1223 } else if (strcmp(name
, "12key") == 0) {
1224 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1231 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1232 ResTable_config
* out
)
1236 if (strcmp(name
, kWildcardName
) == 0) {
1237 mask
= ResTable_config::MASK_NAVHIDDEN
;
1238 value
= ResTable_config::NAVHIDDEN_ANY
;
1239 } else if (strcmp(name
, "navexposed") == 0) {
1240 mask
= ResTable_config::MASK_NAVHIDDEN
;
1241 value
= ResTable_config::NAVHIDDEN_NO
;
1242 } else if (strcmp(name
, "navhidden") == 0) {
1243 mask
= ResTable_config::MASK_NAVHIDDEN
;
1244 value
= ResTable_config::NAVHIDDEN_YES
;
1248 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1255 bool AaptGroupEntry::getNavigationName(const char* name
,
1256 ResTable_config
* out
)
1258 if (strcmp(name
, kWildcardName
) == 0) {
1259 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1261 } else if (strcmp(name
, "nonav") == 0) {
1262 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1264 } else if (strcmp(name
, "dpad") == 0) {
1265 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1267 } else if (strcmp(name
, "trackball") == 0) {
1268 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1270 } else if (strcmp(name
, "wheel") == 0) {
1271 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1278 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1280 if (strcmp(name
, kWildcardName
) == 0) {
1282 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1283 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1288 const char* x
= name
;
1289 while (*x
>= '0' && *x
<= '9') x
++;
1290 if (x
== name
|| *x
!= 'x') return false;
1291 String8
xName(name
, x
-name
);
1295 while (*y
>= '0' && *y
<= '9') y
++;
1296 if (y
== name
|| *y
!= 0) return false;
1297 String8
yName(x
, y
-x
);
1299 uint16_t w
= (uint16_t)atoi(xName
.string());
1300 uint16_t h
= (uint16_t)atoi(yName
.string());
1306 out
->screenWidth
= w
;
1307 out
->screenHeight
= h
;
1313 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1315 if (strcmp(name
, kWildcardName
) == 0) {
1317 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1322 if (*name
!= 's') return false;
1324 if (*name
!= 'w') return false;
1326 const char* x
= name
;
1327 while (*x
>= '0' && *x
<= '9') x
++;
1328 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1329 String8
xName(name
, x
-name
);
1332 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1338 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1340 if (strcmp(name
, kWildcardName
) == 0) {
1342 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1347 if (*name
!= 'w') return false;
1349 const char* x
= name
;
1350 while (*x
>= '0' && *x
<= '9') x
++;
1351 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1352 String8
xName(name
, x
-name
);
1355 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1361 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1363 if (strcmp(name
, kWildcardName
) == 0) {
1365 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1370 if (*name
!= 'h') return false;
1372 const char* x
= name
;
1373 while (*x
>= '0' && *x
<= '9') x
++;
1374 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1375 String8
xName(name
, x
-name
);
1378 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1384 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1386 if (strcmp(name
, kWildcardName
) == 0) {
1388 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1389 out
->minorVersion
= out
->MINORVERSION_ANY
;
1399 const char* s
= name
;
1400 while (*s
>= '0' && *s
<= '9') s
++;
1401 if (s
== name
|| *s
!= 0) return false;
1402 String8
sdkName(name
, s
-name
);
1405 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1406 out
->minorVersion
= 0;
1412 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1414 int v
= mcc
.compare(o
.mcc
);
1415 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1416 if (v
== 0) v
= locale
.compare(o
.locale
);
1417 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1418 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1419 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1420 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1421 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1422 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1423 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1424 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1425 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1426 if (v
== 0) v
= density
.compare(o
.density
);
1427 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1428 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1429 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1430 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1431 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1432 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1433 if (v
== 0) v
= version
.compare(o
.version
);
1437 const ResTable_config
& AaptGroupEntry::toParams() const
1439 if (!mParamsChanged
) {
1443 mParamsChanged
= false;
1444 ResTable_config
& params(mParams
);
1445 memset(¶ms
, 0, sizeof(params
));
1446 getMccName(mcc
.string(), ¶ms
);
1447 getMncName(mnc
.string(), ¶ms
);
1448 getLocaleName(locale
.string(), ¶ms
);
1449 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1450 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1451 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1452 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1453 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1454 getOrientationName(orientation
.string(), ¶ms
);
1455 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1456 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1457 getDensityName(density
.string(), ¶ms
);
1458 getTouchscreenName(touchscreen
.string(), ¶ms
);
1459 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1460 getKeyboardName(keyboard
.string(), ¶ms
);
1461 getNavHiddenName(navHidden
.string(), ¶ms
);
1462 getNavigationName(navigation
.string(), ¶ms
);
1463 getScreenSizeName(screenSize
.string(), ¶ms
);
1464 getVersionName(version
.string(), ¶ms
);
1466 // Fix up version number based on specified parameters.
1468 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1469 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1470 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1471 minSdk
= SDK_HONEYCOMB_MR2
;
1472 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1473 != ResTable_config::UI_MODE_TYPE_ANY
1474 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1475 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1477 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1478 != ResTable_config::SCREENSIZE_ANY
1479 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1480 != ResTable_config::SCREENLONG_ANY
1481 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1485 if (minSdk
> params
.sdkVersion
) {
1486 params
.sdkVersion
= minSdk
;
1492 // =========================================================================
1493 // =========================================================================
1494 // =========================================================================
1496 void* AaptFile::editData(size_t size
)
1498 if (size
<= mBufferSize
) {
1502 size_t allocSize
= (size
*3)/2;
1503 void* buf
= realloc(mData
, allocSize
);
1509 mBufferSize
= allocSize
;
1513 void* AaptFile::editData(size_t* outSize
)
1516 *outSize
= mDataSize
;
1521 void* AaptFile::padData(size_t wordSize
)
1523 const size_t extra
= mDataSize%wordSize
;
1528 size_t initial
= mDataSize
;
1529 void* data
= editData(initial
+(wordSize
-extra
));
1531 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1536 status_t
AaptFile::writeData(const void* data
, size_t size
)
1538 size_t end
= mDataSize
;
1539 size_t total
= size
+ end
;
1540 void* buf
= editData(total
);
1542 return UNKNOWN_ERROR
;
1544 memcpy(((char*)buf
)+end
, data
, size
);
1548 void AaptFile::clearData()
1550 if (mData
!= NULL
) free(mData
);
1556 String8
AaptFile::getPrintableSource() const
1559 String8
name(mGroupEntry
.toDirName(String8()));
1560 name
.appendPath(mPath
);
1561 name
.append(" #generated");
1567 // =========================================================================
1568 // =========================================================================
1569 // =========================================================================
1571 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1573 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1574 file
->mPath
= mPath
;
1575 mFiles
.add(file
->getGroupEntry(), file
);
1580 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1581 file
->getSourceFile().string(),
1582 file
->getGroupEntry().toDirName(String8()).string(),
1583 mLeaf
.string(), mPath
.string());
1586 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1587 getPrintableSource().string());
1588 return UNKNOWN_ERROR
;
1591 void AaptGroup::removeFile(size_t index
)
1593 mFiles
.removeItemsAt(index
);
1596 void AaptGroup::print(const String8
& prefix
) const
1598 printf("%s%s\n", prefix
.string(), getPath().string());
1599 const size_t N
=mFiles
.size();
1601 for (i
=0; i
<N
; i
++) {
1602 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1603 const AaptGroupEntry
& e
= file
->getGroupEntry();
1604 if (file
->hasData()) {
1605 printf("%s Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(),
1606 (int)file
->getSize());
1608 printf("%s Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(),
1609 file
->getPrintableSource().string());
1611 //printf("%s File Group Entry: %s\n", prefix.string(),
1612 // file->getGroupEntry().toDirName(String8()).string());
1616 String8
AaptGroup::getPrintableSource() const
1618 if (mFiles
.size() > 0) {
1619 // Arbitrarily pull the first source file out of the list.
1620 return mFiles
.valueAt(0)->getPrintableSource();
1623 // Should never hit this case, but to be safe...
1628 // =========================================================================
1629 // =========================================================================
1630 // =========================================================================
1632 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1634 if (mFiles
.indexOfKey(name
) >= 0) {
1635 return ALREADY_EXISTS
;
1637 mFiles
.add(name
, file
);
1641 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1643 if (mDirs
.indexOfKey(name
) >= 0) {
1644 return ALREADY_EXISTS
;
1646 mDirs
.add(name
, dir
);
1650 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1653 String8 remain
= path
;
1655 sp
<AaptDir
> subdir
= this;
1656 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1657 subdir
= subdir
->makeDir(name
);
1660 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1662 return subdir
->mDirs
.valueAt(i
);
1664 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1665 subdir
->mDirs
.add(name
, dir
);
1669 void AaptDir::removeFile(const String8
& name
)
1671 mFiles
.removeItem(name
);
1674 void AaptDir::removeDir(const String8
& name
)
1676 mDirs
.removeItem(name
);
1679 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1681 sp
<AaptGroup
> group
;
1682 if (mFiles
.indexOfKey(leafName
) >= 0) {
1683 group
= mFiles
.valueFor(leafName
);
1685 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1686 mFiles
.add(leafName
, group
);
1689 return group
->addFile(file
);
1692 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1693 const AaptGroupEntry
& kind
, const String8
& resType
,
1694 sp
<FilePathStore
>& fullResPaths
)
1696 Vector
<String8
> fileNames
;
1700 dir
= opendir(srcDir
.string());
1702 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1703 return UNKNOWN_ERROR
;
1707 * Slurp the filenames out of the directory.
1710 struct dirent
* entry
;
1712 entry
= readdir(dir
);
1716 if (isHidden(srcDir
.string(), entry
->d_name
))
1719 String8
name(entry
->d_name
);
1720 fileNames
.add(name
);
1721 // Add fully qualified path for dependency purposes
1722 // if we're collecting them
1723 if (fullResPaths
!= NULL
) {
1724 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1733 * Stash away the files and recursively descend into subdirectories.
1735 const size_t N
= fileNames
.size();
1737 for (i
= 0; i
< N
; i
++) {
1738 String8
pathName(srcDir
);
1741 pathName
.appendPath(fileNames
[i
].string());
1742 type
= getFileType(pathName
.string());
1743 if (type
== kFileTypeDirectory
) {
1745 bool notAdded
= false;
1746 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1747 subdir
= mDirs
.valueFor(fileNames
[i
]);
1749 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1752 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1753 resType
, fullResPaths
);
1754 if (res
< NO_ERROR
) {
1757 if (res
> 0 && notAdded
) {
1758 mDirs
.add(fileNames
[i
], subdir
);
1761 } else if (type
== kFileTypeRegular
) {
1762 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1763 status_t err
= addLeafFile(fileNames
[i
], file
);
1764 if (err
!= NO_ERROR
) {
1771 if (bundle
->getVerbose())
1772 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1779 status_t
AaptDir::validate() const
1781 const size_t NF
= mFiles
.size();
1782 const size_t ND
= mDirs
.size();
1784 for (i
= 0; i
< NF
; i
++) {
1785 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1786 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1787 "Invalid filename. Unable to add.");
1788 return UNKNOWN_ERROR
;
1792 for (j
= i
+1; j
< NF
; j
++) {
1793 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1794 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1795 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1796 "File is case-insensitive equivalent to: %s",
1797 mFiles
.valueAt(j
)->getPrintableSource().string());
1798 return UNKNOWN_ERROR
;
1801 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1802 // (this is mostly caught by the "marked" stuff, below)
1805 for (j
= 0; j
< ND
; j
++) {
1806 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1807 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1808 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1809 "File conflicts with dir from: %s",
1810 mDirs
.valueAt(j
)->getPrintableSource().string());
1811 return UNKNOWN_ERROR
;
1816 for (i
= 0; i
< ND
; i
++) {
1817 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1818 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1819 "Invalid directory name, unable to add.");
1820 return UNKNOWN_ERROR
;
1824 for (j
= i
+1; j
< ND
; j
++) {
1825 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1826 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1827 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1828 "Directory is case-insensitive equivalent to: %s",
1829 mDirs
.valueAt(j
)->getPrintableSource().string());
1830 return UNKNOWN_ERROR
;
1834 status_t err
= mDirs
.valueAt(i
)->validate();
1835 if (err
!= NO_ERROR
) {
1843 void AaptDir::print(const String8
& prefix
) const
1845 const size_t ND
=getDirs().size();
1847 for (i
=0; i
<ND
; i
++) {
1848 getDirs().valueAt(i
)->print(prefix
);
1851 const size_t NF
=getFiles().size();
1852 for (i
=0; i
<NF
; i
++) {
1853 getFiles().valueAt(i
)->print(prefix
);
1857 String8
AaptDir::getPrintableSource() const
1859 if (mFiles
.size() > 0) {
1860 // Arbitrarily pull the first file out of the list as the source dir.
1861 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1863 if (mDirs
.size() > 0) {
1864 // Or arbitrarily pull the first dir out of the list as the source dir.
1865 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1868 // Should never hit this case, but to be safe...
1873 // =========================================================================
1874 // =========================================================================
1875 // =========================================================================
1877 status_t
AaptSymbols::applyJavaSymbols(const sp
<AaptSymbols
>& javaSymbols
)
1879 status_t err
= NO_ERROR
;
1880 size_t N
= javaSymbols
->mSymbols
.size();
1881 for (size_t i
=0; i
<N
; i
++) {
1882 const String8
& name
= javaSymbols
->mSymbols
.keyAt(i
);
1883 const AaptSymbolEntry
& entry
= javaSymbols
->mSymbols
.valueAt(i
);
1884 ssize_t pos
= mSymbols
.indexOfKey(name
);
1886 entry
.sourcePos
.error("Symbol '%s' declared with <java-symbol> not defined\n", name
.string());
1887 err
= UNKNOWN_ERROR
;
1890 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1891 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1892 mSymbols
.editValueAt(pos
).isJavaSymbol
= entry
.isJavaSymbol
;
1895 N
= javaSymbols
->mNestedSymbols
.size();
1896 for (size_t i
=0; i
<N
; i
++) {
1897 const String8
& name
= javaSymbols
->mNestedSymbols
.keyAt(i
);
1898 const sp
<AaptSymbols
>& symbols
= javaSymbols
->mNestedSymbols
.valueAt(i
);
1899 ssize_t pos
= mNestedSymbols
.indexOfKey(name
);
1902 pos
.error("Java symbol dir %s not defined\n", name
.string());
1903 err
= UNKNOWN_ERROR
;
1906 //printf("**** applying java symbols in dir %s\n", name.string());
1907 status_t myerr
= mNestedSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
1908 if (myerr
!= NO_ERROR
) {
1916 // =========================================================================
1917 // =========================================================================
1918 // =========================================================================
1920 AaptAssets::AaptAssets()
1921 : AaptDir(String8(), String8()),
1922 mChanged(false), mHaveIncludedAssets(false), mRes(NULL
)
1926 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const {
1929 return mGroupEntries
;
1932 status_t
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1935 return AaptDir::addFile(name
, file
);
1938 sp
<AaptFile
> AaptAssets::addFile(
1939 const String8
& filePath
, const AaptGroupEntry
& entry
,
1940 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1941 const String8
& resType
)
1943 sp
<AaptDir
> dir
= this;
1944 sp
<AaptGroup
> group
;
1946 String8 root
, remain(filePath
), partialPath
;
1947 while (remain
.length() > 0) {
1948 root
= remain
.walkPath(&remain
);
1949 partialPath
.appendPath(root
);
1951 const String8
rootStr(root
);
1953 if (remain
.length() == 0) {
1954 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1956 group
= dir
->getFiles().valueAt(i
);
1958 group
= new AaptGroup(rootStr
, filePath
);
1959 status_t res
= dir
->addFile(rootStr
, group
);
1960 if (res
!= NO_ERROR
) {
1964 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1965 status_t res
= group
->addFile(file
);
1966 if (res
!= NO_ERROR
) {
1972 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1974 dir
= dir
->getDirs().valueAt(i
);
1976 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1977 status_t res
= dir
->addDir(rootStr
, subdir
);
1978 if (res
!= NO_ERROR
) {
1986 mGroupEntries
.add(entry
);
1987 if (outGroup
) *outGroup
= group
;
1991 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1992 const sp
<AaptFile
>& file
, const String8
& resType
)
1994 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1995 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1996 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1997 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
2000 subdir
->addFile(leafName
, grr
);
2004 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
2009 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
2010 const size_t dirCount
=resDirs
.size();
2011 sp
<AaptAssets
> current
= this;
2013 const int N
= bundle
->getFileSpecCount();
2016 * If a package manifest was specified, include that first.
2018 if (bundle
->getAndroidManifestFile() != NULL
) {
2019 // place at root of zip.
2020 String8
srcFile(bundle
->getAndroidManifestFile());
2021 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
2027 * If a directory of custom assets was supplied, slurp 'em up.
2029 if (bundle
->getAssetSourceDir()) {
2030 const char* assetDir
= bundle
->getAssetSourceDir();
2032 FileType type
= getFileType(assetDir
);
2033 if (type
== kFileTypeNonexistent
) {
2034 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
2035 return UNKNOWN_ERROR
;
2037 if (type
!= kFileTypeDirectory
) {
2038 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2039 return UNKNOWN_ERROR
;
2042 String8
assetRoot(assetDir
);
2043 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
2044 AaptGroupEntry group
;
2045 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
2046 String8(), mFullAssetPaths
);
2052 mGroupEntries
.add(group
);
2054 totalCount
+= count
;
2056 if (bundle
->getVerbose())
2057 printf("Found %d custom asset file%s in %s\n",
2058 count
, (count
==1) ? "" : "s", assetDir
);
2062 * If a directory of resource-specific assets was supplied, slurp 'em up.
2064 for (size_t i
=0; i
<dirCount
; i
++) {
2065 const char *res
= resDirs
[i
];
2067 type
= getFileType(res
);
2068 if (type
== kFileTypeNonexistent
) {
2069 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
2070 return UNKNOWN_ERROR
;
2072 if (type
== kFileTypeDirectory
) {
2074 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
2075 current
->setOverlay(nextOverlay
);
2076 current
= nextOverlay
;
2077 current
->setFullResPaths(mFullResPaths
);
2079 count
= current
->slurpResourceTree(bundle
, String8(res
));
2085 totalCount
+= count
;
2088 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
2089 return UNKNOWN_ERROR
;
2095 * Now do any additional raw files.
2097 for (int arg
=0; arg
<N
; arg
++) {
2098 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
2100 FileType type
= getFileType(assetDir
);
2101 if (type
== kFileTypeNonexistent
) {
2102 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
2103 return UNKNOWN_ERROR
;
2105 if (type
!= kFileTypeDirectory
) {
2106 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2107 return UNKNOWN_ERROR
;
2110 String8
assetRoot(assetDir
);
2112 if (bundle
->getVerbose())
2113 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
2116 * Do a recursive traversal of subdir tree. We don't make any
2117 * guarantees about ordering, so we're okay with an inorder search
2118 * using whatever order the OS happens to hand back to us.
2120 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
2122 /* failure; report error and remove archive */
2126 totalCount
+= count
;
2128 if (bundle
->getVerbose())
2129 printf("Found %d asset file%s in %s\n",
2130 count
, (count
==1) ? "" : "s", assetDir
);
2134 if (count
!= NO_ERROR
) {
2139 count
= filter(bundle
);
2140 if (count
!= NO_ERROR
) {
2149 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
2150 const AaptGroupEntry
& kind
,
2151 const String8
& resType
,
2152 sp
<FilePathStore
>& fullResPaths
)
2154 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
2156 mGroupEntries
.add(kind
);
2162 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
2166 DIR* dir
= opendir(srcDir
.string());
2168 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
2169 return UNKNOWN_ERROR
;
2175 * Run through the directory, looking for dirs that match the
2179 struct dirent
* entry
= readdir(dir
);
2180 if (entry
== NULL
) {
2184 if (isHidden(srcDir
.string(), entry
->d_name
)) {
2188 String8
subdirName(srcDir
);
2189 subdirName
.appendPath(entry
->d_name
);
2191 AaptGroupEntry group
;
2193 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
2195 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2201 if (bundle
->getMaxResVersion() != NULL
&& group
.getVersionString().length() != 0) {
2202 int maxResInt
= atoi(bundle
->getMaxResVersion());
2203 const char *verString
= group
.getVersionString().string();
2204 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2205 if (dirVersionInt
> maxResInt
) {
2206 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2211 FileType type
= getFileType(subdirName
.string());
2213 if (type
== kFileTypeDirectory
) {
2214 sp
<AaptDir
> dir
= makeDir(resType
);
2215 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2216 resType
, mFullResPaths
);
2222 mGroupEntries
.add(group
);
2226 // Only add this directory if we don't already have a resource dir
2227 // for the current type. This ensures that we only add the dir once
2229 sp
<AaptDir
> rdir
= resDir(resType
);
2234 if (bundle
->getVerbose()) {
2235 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2251 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2254 SortedVector
<AaptGroupEntry
> entries
;
2256 ZipFile
* zip
= new ZipFile
;
2257 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2258 if (err
!= NO_ERROR
) {
2259 fprintf(stderr
, "error opening zip file %s\n", filename
);
2265 const int N
= zip
->getNumEntries();
2266 for (int i
=0; i
<N
; i
++) {
2267 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2268 if (entry
->getDeleted()) {
2272 String8
entryName(entry
->getFileName());
2274 String8 dirName
= entryName
.getPathDir();
2275 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2278 AaptGroupEntry kind
;
2281 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2282 // these are the resources, pull their type out of the directory name
2283 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2285 // these are untyped and don't have an AaptGroupEntry
2287 if (entries
.indexOf(kind
) < 0) {
2289 mGroupEntries
.add(kind
);
2292 // use the one from the zip file if they both exist.
2293 dir
->removeFile(entryName
.getPathLeaf());
2295 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2296 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2297 if (err
!= NO_ERROR
) {
2298 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2302 file
->setCompressionMethod(entry
->getCompressionMethod());
2305 if (entryName
== "AndroidManifest.xml") {
2306 printf("AndroidManifest.xml\n");
2308 printf("\n\nfile: %s\n", entryName
.string());
2311 size_t len
= entry
->getUncompressedLen();
2312 void* data
= zip
->uncompress(entry
);
2313 void* buf
= file
->editData(len
);
2314 memcpy(buf
, data
, len
);
2318 const unsigned char* p
= (unsigned char*)data
;
2319 const unsigned char* end
= p
+len
;
2321 for (int i
=0; i
<32 && p
< end
; i
++) {
2322 printf("0x%03x ", i
*0x10 + OFF
);
2323 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2324 printf(" %02x", *p
);
2341 status_t
AaptAssets::filter(Bundle
* bundle
)
2343 ResourceFilter reqFilter
;
2344 status_t err
= reqFilter
.parse(bundle
->getConfigurations());
2345 if (err
!= NO_ERROR
) {
2349 ResourceFilter prefFilter
;
2350 err
= prefFilter
.parse(bundle
->getPreferredConfigurations());
2351 if (err
!= NO_ERROR
) {
2355 if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) {
2359 if (bundle
->getVerbose()) {
2360 if (!reqFilter
.isEmpty()) {
2361 printf("Applying required filter: %s\n",
2362 bundle
->getConfigurations());
2364 if (!prefFilter
.isEmpty()) {
2365 printf("Applying preferred filter: %s\n",
2366 bundle
->getPreferredConfigurations());
2370 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2371 const size_t ND
= resdirs
.size();
2372 for (size_t i
=0; i
<ND
; i
++) {
2373 const sp
<AaptDir
>& dir
= resdirs
.itemAt(i
);
2374 if (dir
->getLeaf() == kValuesDir
) {
2375 // The "value" dir is special since a single file defines
2376 // multiple resources, so we can not do filtering on the
2377 // files themselves.
2380 if (dir
->getLeaf() == kMipmapDir
) {
2381 // We also skip the "mipmap" directory, since the point of this
2382 // is to include all densities without stripping. If you put
2383 // other configurations in here as well they won't be stripped
2384 // either... So don't do that. Seriously. What is wrong with you?
2388 const size_t NG
= dir
->getFiles().size();
2389 for (size_t j
=0; j
<NG
; j
++) {
2390 sp
<AaptGroup
> grp
= dir
->getFiles().valueAt(j
);
2392 // First remove any configurations we know we don't need.
2393 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2394 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2395 if (k
== 0 && grp
->getFiles().size() == 1) {
2396 // If this is the only file left, we need to keep it.
2397 // Otherwise the resource IDs we are using will be inconsistent
2398 // with what we get when not stripping. Sucky, but at least
2399 // for now we can rely on the back-end doing another filtering
2400 // pass to take this out and leave us with this resource name
2401 // containing no entries.
2404 if (file
->getPath().getPathExtension() == ".xml") {
2405 // We can't remove .xml files at this point, because when
2406 // we parse them they may add identifier resources, so
2407 // removing them can cause our resource identifiers to
2408 // become inconsistent.
2411 const ResTable_config
& config(file
->getGroupEntry().toParams());
2412 if (!reqFilter
.match(config
)) {
2413 if (bundle
->getVerbose()) {
2414 printf("Pruning unneeded resource: %s\n",
2415 file
->getPrintableSource().string());
2422 // Quick check: no preferred filters, nothing more to do.
2423 if (prefFilter
.isEmpty()) {
2427 // Now deal with preferred configurations.
2428 for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) {
2429 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2430 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2431 if (k
== 0 && grp
->getFiles().size() == 1) {
2432 // If this is the only file left, we need to keep it.
2433 // Otherwise the resource IDs we are using will be inconsistent
2434 // with what we get when not stripping. Sucky, but at least
2435 // for now we can rely on the back-end doing another filtering
2436 // pass to take this out and leave us with this resource name
2437 // containing no entries.
2440 if (file
->getPath().getPathExtension() == ".xml") {
2441 // We can't remove .xml files at this point, because when
2442 // we parse them they may add identifier resources, so
2443 // removing them can cause our resource identifiers to
2444 // become inconsistent.
2447 const ResTable_config
& config(file
->getGroupEntry().toParams());
2448 if (!prefFilter
.match(axis
, config
)) {
2449 // This is a resource we would prefer not to have. Check
2450 // to see if have a similar variation that we would like
2451 // to have and, if so, we can drop it.
2452 for (size_t m
=0; m
<grp
->getFiles().size(); m
++) {
2453 if (m
== k
) continue;
2454 sp
<AaptFile
> mfile
= grp
->getFiles().valueAt(m
);
2455 const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams());
2456 if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) {
2457 if (prefFilter
.match(axis
, mconfig
)) {
2458 if (bundle
->getVerbose()) {
2459 printf("Pruning unneeded resource: %s\n",
2460 file
->getPrintableSource().string());
2477 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2479 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2481 sym
= new AaptSymbols();
2482 mSymbols
.add(name
, sym
);
2487 sp
<AaptSymbols
> AaptAssets::getJavaSymbolsFor(const String8
& name
)
2489 sp
<AaptSymbols
> sym
= mJavaSymbols
.valueFor(name
);
2491 sym
= new AaptSymbols();
2492 mJavaSymbols
.add(name
, sym
);
2497 status_t
AaptAssets::applyJavaSymbols()
2499 size_t N
= mJavaSymbols
.size();
2500 for (size_t i
=0; i
<N
; i
++) {
2501 const String8
& name
= mJavaSymbols
.keyAt(i
);
2502 const sp
<AaptSymbols
>& symbols
= mJavaSymbols
.valueAt(i
);
2503 ssize_t pos
= mSymbols
.indexOfKey(name
);
2506 pos
.error("Java symbol dir %s not defined\n", name
.string());
2507 return UNKNOWN_ERROR
;
2509 //printf("**** applying java symbols in dir %s\n", name.string());
2510 status_t err
= mSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
2511 if (err
!= NO_ERROR
) {
2519 bool AaptAssets::isJavaSymbol(const AaptSymbolEntry
& sym
, bool includePrivate
) const {
2520 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2521 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2522 // sym.isJavaSymbol ? 1 : 0);
2523 if (!mHavePrivateSymbols
) return true;
2524 if (sym
.isPublic
) return true;
2525 if (includePrivate
&& sym
.isJavaSymbol
) return true;
2529 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2531 if (!mHaveIncludedAssets
) {
2532 // Add in all includes.
2533 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2534 const size_t N
=incl
.size();
2535 for (size_t i
=0; i
<N
; i
++) {
2536 if (bundle
->getVerbose())
2537 printf("Including resources from package: %s\n", incl
[i
]);
2538 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2539 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2541 return UNKNOWN_ERROR
;
2544 mHaveIncludedAssets
= true;
2550 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2552 const ResTable
& res
= getIncludedResources();
2554 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2557 const ResTable
& AaptAssets::getIncludedResources() const
2559 return mIncludedAssets
.getResources(false);
2562 void AaptAssets::print(const String8
& prefix
) const
2564 String8
innerPrefix(prefix
);
2565 innerPrefix
.append(" ");
2566 String8
innerInnerPrefix(innerPrefix
);
2567 innerInnerPrefix
.append(" ");
2568 printf("%sConfigurations:\n", prefix
.string());
2569 const size_t N
=mGroupEntries
.size();
2570 for (size_t i
=0; i
<N
; i
++) {
2571 String8 cname
= mGroupEntries
.itemAt(i
).toDirName(String8());
2572 printf("%s %s\n", prefix
.string(),
2573 cname
!= "" ? cname
.string() : "(default)");
2576 printf("\n%sFiles:\n", prefix
.string());
2577 AaptDir::print(innerPrefix
);
2579 printf("\n%sResource Dirs:\n", prefix
.string());
2580 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2581 const size_t NR
= resdirs
.size();
2582 for (size_t i
=0; i
<NR
; i
++) {
2583 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2584 printf("%s Type %s\n", prefix
.string(), d
->getLeaf().string());
2585 d
->print(innerInnerPrefix
);
2589 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const
2591 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2592 const size_t N
= resdirs
.size();
2593 for (size_t i
=0; i
<N
; i
++) {
2594 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2595 if (d
->getLeaf() == name
) {
2603 valid_symbol_name(const String8
& symbol
)
2605 static char const * const KEYWORDS
[] = {
2606 "abstract", "assert", "boolean", "break",
2607 "byte", "case", "catch", "char", "class", "const", "continue",
2608 "default", "do", "double", "else", "enum", "extends", "final",
2609 "finally", "float", "for", "goto", "if", "implements", "import",
2610 "instanceof", "int", "interface", "long", "native", "new", "package",
2611 "private", "protected", "public", "return", "short", "static",
2612 "strictfp", "super", "switch", "synchronized", "this", "throw",
2613 "throws", "transient", "try", "void", "volatile", "while",
2614 "true", "false", "null",
2617 const char*const* k
= KEYWORDS
;
2618 const char*const s
= symbol
.string();
2620 if (0 == strcmp(s
, *k
)) {