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]);
186 // smallest screen dp width
187 if (getSmallestScreenWidthDpName(part
.string(), &config
)) {
188 *axis
= AXIS_SMALLESTSCREENWIDTHDP
;
189 *value
= config
.smallestScreenWidthDp
;
194 if (getScreenWidthDpName(part
.string(), &config
)) {
195 *axis
= AXIS_SCREENWIDTHDP
;
196 *value
= config
.screenWidthDp
;
201 if (getScreenHeightDpName(part
.string(), &config
)) {
202 *axis
= AXIS_SCREENHEIGHTDP
;
203 *value
= config
.screenHeightDp
;
207 // screen layout size
208 if (getScreenLayoutSizeName(part
.string(), &config
)) {
209 *axis
= AXIS_SCREENLAYOUTSIZE
;
210 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
214 // screen layout long
215 if (getScreenLayoutLongName(part
.string(), &config
)) {
216 *axis
= AXIS_SCREENLAYOUTLONG
;
217 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
222 if (getOrientationName(part
.string(), &config
)) {
223 *axis
= AXIS_ORIENTATION
;
224 *value
= config
.orientation
;
229 if (getUiModeTypeName(part
.string(), &config
)) {
230 *axis
= AXIS_UIMODETYPE
;
231 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
236 if (getUiModeNightName(part
.string(), &config
)) {
237 *axis
= AXIS_UIMODENIGHT
;
238 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
243 if (getDensityName(part
.string(), &config
)) {
244 *axis
= AXIS_DENSITY
;
245 *value
= config
.density
;
250 if (getTouchscreenName(part
.string(), &config
)) {
251 *axis
= AXIS_TOUCHSCREEN
;
252 *value
= config
.touchscreen
;
257 if (getKeysHiddenName(part
.string(), &config
)) {
258 *axis
= AXIS_KEYSHIDDEN
;
259 *value
= config
.inputFlags
;
264 if (getKeyboardName(part
.string(), &config
)) {
265 *axis
= AXIS_KEYBOARD
;
266 *value
= config
.keyboard
;
271 if (getNavHiddenName(part
.string(), &config
)) {
272 *axis
= AXIS_NAVHIDDEN
;
273 *value
= config
.inputFlags
;
278 if (getNavigationName(part
.string(), &config
)) {
279 *axis
= AXIS_NAVIGATION
;
280 *value
= config
.navigation
;
285 if (getScreenSizeName(part
.string(), &config
)) {
286 *axis
= AXIS_SCREENSIZE
;
287 *value
= config
.screenSize
;
292 if (getVersionName(part
.string(), &config
)) {
293 *axis
= AXIS_VERSION
;
294 *value
= config
.version
;
302 AaptGroupEntry::getConfigValueForAxis(const ResTable_config
& config
, int axis
)
310 return (((uint32_t)config
.country
[1]) << 24) | (((uint32_t)config
.country
[0]) << 16)
311 | (((uint32_t)config
.language
[1]) << 8) | (config
.language
[0]);
312 case AXIS_SCREENLAYOUTSIZE
:
313 return config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
;
314 case AXIS_ORIENTATION
:
315 return config
.orientation
;
316 case AXIS_UIMODETYPE
:
317 return (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
318 case AXIS_UIMODENIGHT
:
319 return (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
321 return config
.density
;
322 case AXIS_TOUCHSCREEN
:
323 return config
.touchscreen
;
324 case AXIS_KEYSHIDDEN
:
325 return config
.inputFlags
;
327 return config
.keyboard
;
328 case AXIS_NAVIGATION
:
329 return config
.navigation
;
330 case AXIS_SCREENSIZE
:
331 return config
.screenSize
;
332 case AXIS_SMALLESTSCREENWIDTHDP
:
333 return config
.smallestScreenWidthDp
;
334 case AXIS_SCREENWIDTHDP
:
335 return config
.screenWidthDp
;
336 case AXIS_SCREENHEIGHTDP
:
337 return config
.screenHeightDp
;
339 return config
.version
;
345 AaptGroupEntry::configSameExcept(const ResTable_config
& config
,
346 const ResTable_config
& otherConfig
, int axis
)
348 for (int i
=AXIS_START
; i
<=AXIS_END
; i
++) {
352 if (getConfigValueForAxis(config
, i
) != getConfigValueForAxis(otherConfig
, i
)) {
360 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
362 mParamsChanged
= true;
364 Vector
<String8
> parts
;
366 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
367 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
;
368 String8 uiModeType
, uiModeNight
, smallestwidthdp
, widthdp
, heightdp
;
372 while (NULL
!= (q
= strchr(p
, '-'))) {
376 //printf("part: %s\n", parts[parts.size()-1].string());
382 //printf("part: %s\n", parts[parts.size()-1].string());
384 const int N
= parts
.size();
386 String8 part
= parts
[index
];
389 if (!isValidResourceType(part
)) {
401 if (getMccName(part
.string())) {
410 //printf("not mcc: %s\n", part.string());
414 if (getMncName(part
.string())) {
423 //printf("not mcc: %s\n", part.string());
427 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
436 //printf("not language: %s\n", part.string());
441 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
444 loc
+= part
.string() + 1;
452 //printf("not region: %s\n", part.string());
455 if (getSmallestScreenWidthDpName(part
.string())) {
456 smallestwidthdp
= part
;
464 //printf("not smallest screen width dp: %s\n", part.string());
467 if (getScreenWidthDpName(part
.string())) {
476 //printf("not screen width dp: %s\n", part.string());
479 if (getScreenHeightDpName(part
.string())) {
488 //printf("not screen height dp: %s\n", part.string());
491 if (getScreenLayoutSizeName(part
.string())) {
500 //printf("not screen layout size: %s\n", part.string());
503 if (getScreenLayoutLongName(part
.string())) {
512 //printf("not screen layout long: %s\n", part.string());
516 if (getOrientationName(part
.string())) {
525 //printf("not orientation: %s\n", part.string());
529 if (getUiModeTypeName(part
.string())) {
538 //printf("not ui mode type: %s\n", part.string());
542 if (getUiModeNightName(part
.string())) {
551 //printf("not ui mode night: %s\n", part.string());
555 if (getDensityName(part
.string())) {
564 //printf("not density: %s\n", part.string());
568 if (getTouchscreenName(part
.string())) {
577 //printf("not touchscreen: %s\n", part.string());
581 if (getKeysHiddenName(part
.string())) {
590 //printf("not keysHidden: %s\n", part.string());
594 if (getKeyboardName(part
.string())) {
603 //printf("not keyboard: %s\n", part.string());
607 if (getNavHiddenName(part
.string())) {
616 //printf("not navHidden: %s\n", part.string());
619 if (getNavigationName(part
.string())) {
628 //printf("not navigation: %s\n", part.string());
631 if (getScreenSizeName(part
.string())) {
640 //printf("not screen size: %s\n", part.string());
643 if (getVersionName(part
.string())) {
652 //printf("not version: %s\n", part.string());
655 // if there are extra parts, it doesn't match
662 this->screenLayoutSize
= layoutsize
;
663 this->screenLayoutLong
= layoutlong
;
664 this->smallestScreenWidthDp
= smallestwidthdp
;
665 this->screenWidthDp
= widthdp
;
666 this->screenHeightDp
= heightdp
;
667 this->orientation
= orient
;
668 this->uiModeType
= uiModeType
;
669 this->uiModeNight
= uiModeNight
;
671 this->touchscreen
= touch
;
672 this->keysHidden
= keysHidden
;
673 this->keyboard
= key
;
674 this->navHidden
= navHidden
;
675 this->navigation
= nav
;
676 this->screenSize
= size
;
677 this->version
= vers
;
679 // what is this anyway?
686 AaptGroupEntry::toString() const
688 String8 s
= this->mcc
;
694 s
+= smallestScreenWidthDp
;
700 s
+= screenLayoutSize
;
702 s
+= screenLayoutLong
;
704 s
+= this->orientation
;
729 AaptGroupEntry::toDirName(const String8
& resType
) const
732 if (this->mcc
!= "") {
733 if (s
.length() > 0) {
738 if (this->mnc
!= "") {
739 if (s
.length() > 0) {
744 if (this->locale
!= "") {
745 if (s
.length() > 0) {
750 if (this->smallestScreenWidthDp
!= "") {
751 if (s
.length() > 0) {
754 s
+= smallestScreenWidthDp
;
756 if (this->screenWidthDp
!= "") {
757 if (s
.length() > 0) {
762 if (this->screenHeightDp
!= "") {
763 if (s
.length() > 0) {
768 if (this->screenLayoutSize
!= "") {
769 if (s
.length() > 0) {
772 s
+= screenLayoutSize
;
774 if (this->screenLayoutLong
!= "") {
775 if (s
.length() > 0) {
778 s
+= screenLayoutLong
;
780 if (this->orientation
!= "") {
781 if (s
.length() > 0) {
786 if (this->uiModeType
!= "") {
787 if (s
.length() > 0) {
792 if (this->uiModeNight
!= "") {
793 if (s
.length() > 0) {
798 if (this->density
!= "") {
799 if (s
.length() > 0) {
804 if (this->touchscreen
!= "") {
805 if (s
.length() > 0) {
810 if (this->keysHidden
!= "") {
811 if (s
.length() > 0) {
816 if (this->keyboard
!= "") {
817 if (s
.length() > 0) {
822 if (this->navHidden
!= "") {
823 if (s
.length() > 0) {
828 if (this->navigation
!= "") {
829 if (s
.length() > 0) {
834 if (this->screenSize
!= "") {
835 if (s
.length() > 0) {
840 if (this->version
!= "") {
841 if (s
.length() > 0) {
850 bool AaptGroupEntry::getMccName(const char* name
,
851 ResTable_config
* out
)
853 if (strcmp(name
, kWildcardName
) == 0) {
854 if (out
) out
->mcc
= 0;
857 const char* c
= name
;
858 if (tolower(*c
) != 'm') return false;
860 if (tolower(*c
) != 'c') return false;
862 if (tolower(*c
) != 'c') return false;
867 while (*c
>= '0' && *c
<= '9') {
870 if (*c
!= 0) return false;
871 if (c
-val
!= 3) return false;
875 if (out
) out
->mcc
= d
;
882 bool AaptGroupEntry::getMncName(const char* name
,
883 ResTable_config
* out
)
885 if (strcmp(name
, kWildcardName
) == 0) {
886 if (out
) out
->mcc
= 0;
889 const char* c
= name
;
890 if (tolower(*c
) != 'm') return false;
892 if (tolower(*c
) != 'n') return false;
894 if (tolower(*c
) != 'c') return false;
899 while (*c
>= '0' && *c
<= '9') {
902 if (*c
!= 0) return false;
903 if (c
-val
== 0 || c
-val
> 3) return false;
906 out
->mnc
= atoi(val
);
913 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
916 * TODO: Should insist that the first two letters are lower case, and the
917 * second two are upper.
919 bool AaptGroupEntry::getLocaleName(const char* fileName
,
920 ResTable_config
* out
)
922 if (strcmp(fileName
, kWildcardName
) == 0
923 || strcmp(fileName
, kDefaultLocale
) == 0) {
925 out
->language
[0] = 0;
926 out
->language
[1] = 0;
933 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
935 out
->language
[0] = fileName
[0];
936 out
->language
[1] = fileName
[1];
943 if (strlen(fileName
) == 5 &&
944 isalpha(fileName
[0]) &&
945 isalpha(fileName
[1]) &&
946 fileName
[2] == '-' &&
947 isalpha(fileName
[3]) &&
948 isalpha(fileName
[4])) {
950 out
->language
[0] = fileName
[0];
951 out
->language
[1] = fileName
[1];
952 out
->country
[0] = fileName
[3];
953 out
->country
[1] = fileName
[4];
961 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
962 ResTable_config
* out
)
964 if (strcmp(name
, kWildcardName
) == 0) {
965 if (out
) out
->screenLayout
=
966 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
967 | ResTable_config::SCREENSIZE_ANY
;
969 } else if (strcmp(name
, "small") == 0) {
970 if (out
) out
->screenLayout
=
971 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
972 | ResTable_config::SCREENSIZE_SMALL
;
974 } else if (strcmp(name
, "normal") == 0) {
975 if (out
) out
->screenLayout
=
976 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
977 | ResTable_config::SCREENSIZE_NORMAL
;
979 } else if (strcmp(name
, "large") == 0) {
980 if (out
) out
->screenLayout
=
981 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
982 | ResTable_config::SCREENSIZE_LARGE
;
984 } else if (strcmp(name
, "xlarge") == 0) {
985 if (out
) out
->screenLayout
=
986 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
987 | ResTable_config::SCREENSIZE_XLARGE
;
994 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
995 ResTable_config
* out
)
997 if (strcmp(name
, kWildcardName
) == 0) {
998 if (out
) out
->screenLayout
=
999 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1000 | ResTable_config::SCREENLONG_ANY
;
1002 } else if (strcmp(name
, "long") == 0) {
1003 if (out
) out
->screenLayout
=
1004 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1005 | ResTable_config::SCREENLONG_YES
;
1007 } else if (strcmp(name
, "notlong") == 0) {
1008 if (out
) out
->screenLayout
=
1009 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
1010 | ResTable_config::SCREENLONG_NO
;
1017 bool AaptGroupEntry::getOrientationName(const char* name
,
1018 ResTable_config
* out
)
1020 if (strcmp(name
, kWildcardName
) == 0) {
1021 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
1023 } else if (strcmp(name
, "port") == 0) {
1024 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
1026 } else if (strcmp(name
, "land") == 0) {
1027 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
1029 } else if (strcmp(name
, "square") == 0) {
1030 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
1037 bool AaptGroupEntry::getUiModeTypeName(const char* name
,
1038 ResTable_config
* out
)
1040 if (strcmp(name
, kWildcardName
) == 0) {
1041 if (out
) out
->uiMode
=
1042 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1043 | ResTable_config::UI_MODE_TYPE_ANY
;
1045 } else if (strcmp(name
, "desk") == 0) {
1046 if (out
) out
->uiMode
=
1047 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1048 | ResTable_config::UI_MODE_TYPE_DESK
;
1050 } else if (strcmp(name
, "car") == 0) {
1051 if (out
) out
->uiMode
=
1052 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1053 | ResTable_config::UI_MODE_TYPE_CAR
;
1055 } else if (strcmp(name
, "television") == 0) {
1056 if (out
) out
->uiMode
=
1057 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1058 | ResTable_config::UI_MODE_TYPE_TELEVISION
;
1060 } else if (strcmp(name
, "appliance") == 0) {
1061 if (out
) out
->uiMode
=
1062 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1063 | ResTable_config::UI_MODE_TYPE_APPLIANCE
;
1070 bool AaptGroupEntry::getUiModeNightName(const char* name
,
1071 ResTable_config
* out
)
1073 if (strcmp(name
, kWildcardName
) == 0) {
1074 if (out
) out
->uiMode
=
1075 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1076 | ResTable_config::UI_MODE_NIGHT_ANY
;
1078 } else if (strcmp(name
, "night") == 0) {
1079 if (out
) out
->uiMode
=
1080 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1081 | ResTable_config::UI_MODE_NIGHT_YES
;
1083 } else if (strcmp(name
, "notnight") == 0) {
1084 if (out
) out
->uiMode
=
1085 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1086 | ResTable_config::UI_MODE_NIGHT_NO
;
1093 bool AaptGroupEntry::getDensityName(const char* name
,
1094 ResTable_config
* out
)
1096 if (strcmp(name
, kWildcardName
) == 0) {
1097 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
1101 if (strcmp(name
, "nodpi") == 0) {
1102 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
1106 if (strcmp(name
, "ldpi") == 0) {
1107 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
1111 if (strcmp(name
, "mdpi") == 0) {
1112 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
1116 if (strcmp(name
, "tvdpi") == 0) {
1117 if (out
) out
->density
= ResTable_config::DENSITY_TV
;
1121 if (strcmp(name
, "hdpi") == 0) {
1122 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
1126 if (strcmp(name
, "xhdpi") == 0) {
1127 if (out
) out
->density
= ResTable_config::DENSITY_XHIGH
;
1131 if (strcmp(name
, "xxhdpi") == 0) {
1132 if (out
) out
->density
= ResTable_config::DENSITY_XXHIGH
;
1136 char* c
= (char*)name
;
1137 while (*c
>= '0' && *c
<= '9') {
1141 // check that we have 'dpi' after the last digit.
1142 if (toupper(c
[0]) != 'D' ||
1143 toupper(c
[1]) != 'P' ||
1144 toupper(c
[2]) != 'I' ||
1149 // temporarily replace the first letter with \0 to
1158 if (out
) out
->density
= d
;
1165 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1166 ResTable_config
* out
)
1168 if (strcmp(name
, kWildcardName
) == 0) {
1169 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1171 } else if (strcmp(name
, "notouch") == 0) {
1172 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1174 } else if (strcmp(name
, "stylus") == 0) {
1175 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1177 } else if (strcmp(name
, "finger") == 0) {
1178 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1185 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1186 ResTable_config
* out
)
1190 if (strcmp(name
, kWildcardName
) == 0) {
1191 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1192 value
= ResTable_config::KEYSHIDDEN_ANY
;
1193 } else if (strcmp(name
, "keysexposed") == 0) {
1194 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1195 value
= ResTable_config::KEYSHIDDEN_NO
;
1196 } else if (strcmp(name
, "keyshidden") == 0) {
1197 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1198 value
= ResTable_config::KEYSHIDDEN_YES
;
1199 } else if (strcmp(name
, "keyssoft") == 0) {
1200 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1201 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1205 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1212 bool AaptGroupEntry::getKeyboardName(const char* name
,
1213 ResTable_config
* out
)
1215 if (strcmp(name
, kWildcardName
) == 0) {
1216 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1218 } else if (strcmp(name
, "nokeys") == 0) {
1219 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1221 } else if (strcmp(name
, "qwerty") == 0) {
1222 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1224 } else if (strcmp(name
, "12key") == 0) {
1225 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1232 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1233 ResTable_config
* out
)
1237 if (strcmp(name
, kWildcardName
) == 0) {
1238 mask
= ResTable_config::MASK_NAVHIDDEN
;
1239 value
= ResTable_config::NAVHIDDEN_ANY
;
1240 } else if (strcmp(name
, "navexposed") == 0) {
1241 mask
= ResTable_config::MASK_NAVHIDDEN
;
1242 value
= ResTable_config::NAVHIDDEN_NO
;
1243 } else if (strcmp(name
, "navhidden") == 0) {
1244 mask
= ResTable_config::MASK_NAVHIDDEN
;
1245 value
= ResTable_config::NAVHIDDEN_YES
;
1249 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1256 bool AaptGroupEntry::getNavigationName(const char* name
,
1257 ResTable_config
* out
)
1259 if (strcmp(name
, kWildcardName
) == 0) {
1260 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1262 } else if (strcmp(name
, "nonav") == 0) {
1263 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1265 } else if (strcmp(name
, "dpad") == 0) {
1266 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1268 } else if (strcmp(name
, "trackball") == 0) {
1269 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1271 } else if (strcmp(name
, "wheel") == 0) {
1272 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1279 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1281 if (strcmp(name
, kWildcardName
) == 0) {
1283 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1284 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1289 const char* x
= name
;
1290 while (*x
>= '0' && *x
<= '9') x
++;
1291 if (x
== name
|| *x
!= 'x') return false;
1292 String8
xName(name
, x
-name
);
1296 while (*y
>= '0' && *y
<= '9') y
++;
1297 if (y
== name
|| *y
!= 0) return false;
1298 String8
yName(x
, y
-x
);
1300 uint16_t w
= (uint16_t)atoi(xName
.string());
1301 uint16_t h
= (uint16_t)atoi(yName
.string());
1307 out
->screenWidth
= w
;
1308 out
->screenHeight
= h
;
1314 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1316 if (strcmp(name
, kWildcardName
) == 0) {
1318 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1323 if (*name
!= 's') return false;
1325 if (*name
!= 'w') return false;
1327 const char* x
= name
;
1328 while (*x
>= '0' && *x
<= '9') x
++;
1329 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1330 String8
xName(name
, x
-name
);
1333 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1339 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1341 if (strcmp(name
, kWildcardName
) == 0) {
1343 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1348 if (*name
!= 'w') return false;
1350 const char* x
= name
;
1351 while (*x
>= '0' && *x
<= '9') x
++;
1352 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1353 String8
xName(name
, x
-name
);
1356 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1362 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1364 if (strcmp(name
, kWildcardName
) == 0) {
1366 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1371 if (*name
!= 'h') return false;
1373 const char* x
= name
;
1374 while (*x
>= '0' && *x
<= '9') x
++;
1375 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1376 String8
xName(name
, x
-name
);
1379 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1385 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1387 if (strcmp(name
, kWildcardName
) == 0) {
1389 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1390 out
->minorVersion
= out
->MINORVERSION_ANY
;
1400 const char* s
= name
;
1401 while (*s
>= '0' && *s
<= '9') s
++;
1402 if (s
== name
|| *s
!= 0) return false;
1403 String8
sdkName(name
, s
-name
);
1406 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1407 out
->minorVersion
= 0;
1413 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1415 int v
= mcc
.compare(o
.mcc
);
1416 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1417 if (v
== 0) v
= locale
.compare(o
.locale
);
1418 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1419 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1420 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1421 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1422 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1423 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1424 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1425 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1426 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1427 if (v
== 0) v
= density
.compare(o
.density
);
1428 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1429 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1430 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1431 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1432 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1433 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1434 if (v
== 0) v
= version
.compare(o
.version
);
1438 const ResTable_config
& AaptGroupEntry::toParams() const
1440 if (!mParamsChanged
) {
1444 mParamsChanged
= false;
1445 ResTable_config
& params(mParams
);
1446 memset(¶ms
, 0, sizeof(params
));
1447 getMccName(mcc
.string(), ¶ms
);
1448 getMncName(mnc
.string(), ¶ms
);
1449 getLocaleName(locale
.string(), ¶ms
);
1450 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1451 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1452 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1453 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1454 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1455 getOrientationName(orientation
.string(), ¶ms
);
1456 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1457 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1458 getDensityName(density
.string(), ¶ms
);
1459 getTouchscreenName(touchscreen
.string(), ¶ms
);
1460 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1461 getKeyboardName(keyboard
.string(), ¶ms
);
1462 getNavHiddenName(navHidden
.string(), ¶ms
);
1463 getNavigationName(navigation
.string(), ¶ms
);
1464 getScreenSizeName(screenSize
.string(), ¶ms
);
1465 getVersionName(version
.string(), ¶ms
);
1467 // Fix up version number based on specified parameters.
1469 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1470 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1471 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1472 minSdk
= SDK_HONEYCOMB_MR2
;
1473 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1474 != ResTable_config::UI_MODE_TYPE_ANY
1475 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1476 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1478 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1479 != ResTable_config::SCREENSIZE_ANY
1480 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1481 != ResTable_config::SCREENLONG_ANY
1482 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1486 if (minSdk
> params
.sdkVersion
) {
1487 params
.sdkVersion
= minSdk
;
1493 // =========================================================================
1494 // =========================================================================
1495 // =========================================================================
1497 void* AaptFile::editData(size_t size
)
1499 if (size
<= mBufferSize
) {
1503 size_t allocSize
= (size
*3)/2;
1504 void* buf
= realloc(mData
, allocSize
);
1510 mBufferSize
= allocSize
;
1514 void* AaptFile::editData(size_t* outSize
)
1517 *outSize
= mDataSize
;
1522 void* AaptFile::padData(size_t wordSize
)
1524 const size_t extra
= mDataSize%wordSize
;
1529 size_t initial
= mDataSize
;
1530 void* data
= editData(initial
+(wordSize
-extra
));
1532 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1537 status_t
AaptFile::writeData(const void* data
, size_t size
)
1539 size_t end
= mDataSize
;
1540 size_t total
= size
+ end
;
1541 void* buf
= editData(total
);
1543 return UNKNOWN_ERROR
;
1545 memcpy(((char*)buf
)+end
, data
, size
);
1549 void AaptFile::clearData()
1551 if (mData
!= NULL
) free(mData
);
1557 String8
AaptFile::getPrintableSource() const
1560 String8
name(mGroupEntry
.toDirName(String8()));
1561 name
.appendPath(mPath
);
1562 name
.append(" #generated");
1568 // =========================================================================
1569 // =========================================================================
1570 // =========================================================================
1572 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1574 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1575 file
->mPath
= mPath
;
1576 mFiles
.add(file
->getGroupEntry(), file
);
1581 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1582 file
->getSourceFile().string(),
1583 file
->getGroupEntry().toDirName(String8()).string(),
1584 mLeaf
.string(), mPath
.string());
1587 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1588 getPrintableSource().string());
1589 return UNKNOWN_ERROR
;
1592 void AaptGroup::removeFile(size_t index
)
1594 mFiles
.removeItemsAt(index
);
1597 void AaptGroup::print(const String8
& prefix
) const
1599 printf("%s%s\n", prefix
.string(), getPath().string());
1600 const size_t N
=mFiles
.size();
1602 for (i
=0; i
<N
; i
++) {
1603 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1604 const AaptGroupEntry
& e
= file
->getGroupEntry();
1605 if (file
->hasData()) {
1606 printf("%s Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(),
1607 (int)file
->getSize());
1609 printf("%s Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(),
1610 file
->getPrintableSource().string());
1612 //printf("%s File Group Entry: %s\n", prefix.string(),
1613 // file->getGroupEntry().toDirName(String8()).string());
1617 String8
AaptGroup::getPrintableSource() const
1619 if (mFiles
.size() > 0) {
1620 // Arbitrarily pull the first source file out of the list.
1621 return mFiles
.valueAt(0)->getPrintableSource();
1624 // Should never hit this case, but to be safe...
1629 // =========================================================================
1630 // =========================================================================
1631 // =========================================================================
1633 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1635 if (mFiles
.indexOfKey(name
) >= 0) {
1636 return ALREADY_EXISTS
;
1638 mFiles
.add(name
, file
);
1642 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1644 if (mDirs
.indexOfKey(name
) >= 0) {
1645 return ALREADY_EXISTS
;
1647 mDirs
.add(name
, dir
);
1651 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1654 String8 remain
= path
;
1656 sp
<AaptDir
> subdir
= this;
1657 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1658 subdir
= subdir
->makeDir(name
);
1661 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1663 return subdir
->mDirs
.valueAt(i
);
1665 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1666 subdir
->mDirs
.add(name
, dir
);
1670 void AaptDir::removeFile(const String8
& name
)
1672 mFiles
.removeItem(name
);
1675 void AaptDir::removeDir(const String8
& name
)
1677 mDirs
.removeItem(name
);
1680 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1682 sp
<AaptGroup
> group
;
1683 if (mFiles
.indexOfKey(leafName
) >= 0) {
1684 group
= mFiles
.valueFor(leafName
);
1686 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1687 mFiles
.add(leafName
, group
);
1690 return group
->addFile(file
);
1693 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1694 const AaptGroupEntry
& kind
, const String8
& resType
,
1695 sp
<FilePathStore
>& fullResPaths
)
1697 Vector
<String8
> fileNames
;
1701 dir
= opendir(srcDir
.string());
1703 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1704 return UNKNOWN_ERROR
;
1708 * Slurp the filenames out of the directory.
1711 struct dirent
* entry
;
1713 entry
= readdir(dir
);
1717 if (isHidden(srcDir
.string(), entry
->d_name
))
1720 String8
name(entry
->d_name
);
1721 fileNames
.add(name
);
1722 // Add fully qualified path for dependency purposes
1723 // if we're collecting them
1724 if (fullResPaths
!= NULL
) {
1725 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1734 * Stash away the files and recursively descend into subdirectories.
1736 const size_t N
= fileNames
.size();
1738 for (i
= 0; i
< N
; i
++) {
1739 String8
pathName(srcDir
);
1742 pathName
.appendPath(fileNames
[i
].string());
1743 type
= getFileType(pathName
.string());
1744 if (type
== kFileTypeDirectory
) {
1746 bool notAdded
= false;
1747 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1748 subdir
= mDirs
.valueFor(fileNames
[i
]);
1750 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1753 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1754 resType
, fullResPaths
);
1755 if (res
< NO_ERROR
) {
1758 if (res
> 0 && notAdded
) {
1759 mDirs
.add(fileNames
[i
], subdir
);
1762 } else if (type
== kFileTypeRegular
) {
1763 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1764 status_t err
= addLeafFile(fileNames
[i
], file
);
1765 if (err
!= NO_ERROR
) {
1772 if (bundle
->getVerbose())
1773 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1780 status_t
AaptDir::validate() const
1782 const size_t NF
= mFiles
.size();
1783 const size_t ND
= mDirs
.size();
1785 for (i
= 0; i
< NF
; i
++) {
1786 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1787 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1788 "Invalid filename. Unable to add.");
1789 return UNKNOWN_ERROR
;
1793 for (j
= i
+1; j
< NF
; j
++) {
1794 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1795 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1796 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1797 "File is case-insensitive equivalent to: %s",
1798 mFiles
.valueAt(j
)->getPrintableSource().string());
1799 return UNKNOWN_ERROR
;
1802 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1803 // (this is mostly caught by the "marked" stuff, below)
1806 for (j
= 0; j
< ND
; j
++) {
1807 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1808 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1809 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1810 "File conflicts with dir from: %s",
1811 mDirs
.valueAt(j
)->getPrintableSource().string());
1812 return UNKNOWN_ERROR
;
1817 for (i
= 0; i
< ND
; i
++) {
1818 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1819 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1820 "Invalid directory name, unable to add.");
1821 return UNKNOWN_ERROR
;
1825 for (j
= i
+1; j
< ND
; j
++) {
1826 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1827 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1828 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1829 "Directory is case-insensitive equivalent to: %s",
1830 mDirs
.valueAt(j
)->getPrintableSource().string());
1831 return UNKNOWN_ERROR
;
1835 status_t err
= mDirs
.valueAt(i
)->validate();
1836 if (err
!= NO_ERROR
) {
1844 void AaptDir::print(const String8
& prefix
) const
1846 const size_t ND
=getDirs().size();
1848 for (i
=0; i
<ND
; i
++) {
1849 getDirs().valueAt(i
)->print(prefix
);
1852 const size_t NF
=getFiles().size();
1853 for (i
=0; i
<NF
; i
++) {
1854 getFiles().valueAt(i
)->print(prefix
);
1858 String8
AaptDir::getPrintableSource() const
1860 if (mFiles
.size() > 0) {
1861 // Arbitrarily pull the first file out of the list as the source dir.
1862 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1864 if (mDirs
.size() > 0) {
1865 // Or arbitrarily pull the first dir out of the list as the source dir.
1866 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1869 // Should never hit this case, but to be safe...
1874 // =========================================================================
1875 // =========================================================================
1876 // =========================================================================
1878 status_t
AaptSymbols::applyJavaSymbols(const sp
<AaptSymbols
>& javaSymbols
)
1880 status_t err
= NO_ERROR
;
1881 size_t N
= javaSymbols
->mSymbols
.size();
1882 for (size_t i
=0; i
<N
; i
++) {
1883 const String8
& name
= javaSymbols
->mSymbols
.keyAt(i
);
1884 const AaptSymbolEntry
& entry
= javaSymbols
->mSymbols
.valueAt(i
);
1885 ssize_t pos
= mSymbols
.indexOfKey(name
);
1887 entry
.sourcePos
.error("Symbol '%s' declared with <java-symbol> not defined\n", name
.string());
1888 err
= UNKNOWN_ERROR
;
1891 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1892 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1893 mSymbols
.editValueAt(pos
).isJavaSymbol
= entry
.isJavaSymbol
;
1896 N
= javaSymbols
->mNestedSymbols
.size();
1897 for (size_t i
=0; i
<N
; i
++) {
1898 const String8
& name
= javaSymbols
->mNestedSymbols
.keyAt(i
);
1899 const sp
<AaptSymbols
>& symbols
= javaSymbols
->mNestedSymbols
.valueAt(i
);
1900 ssize_t pos
= mNestedSymbols
.indexOfKey(name
);
1903 pos
.error("Java symbol dir %s not defined\n", name
.string());
1904 err
= UNKNOWN_ERROR
;
1907 //printf("**** applying java symbols in dir %s\n", name.string());
1908 status_t myerr
= mNestedSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
1909 if (myerr
!= NO_ERROR
) {
1917 // =========================================================================
1918 // =========================================================================
1919 // =========================================================================
1921 AaptAssets::AaptAssets()
1922 : AaptDir(String8(), String8()),
1923 mChanged(false), mHaveIncludedAssets(false), mRes(NULL
)
1927 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const {
1930 return mGroupEntries
;
1933 status_t
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1936 return AaptDir::addFile(name
, file
);
1939 sp
<AaptFile
> AaptAssets::addFile(
1940 const String8
& filePath
, const AaptGroupEntry
& entry
,
1941 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1942 const String8
& resType
)
1944 sp
<AaptDir
> dir
= this;
1945 sp
<AaptGroup
> group
;
1947 String8 root
, remain(filePath
), partialPath
;
1948 while (remain
.length() > 0) {
1949 root
= remain
.walkPath(&remain
);
1950 partialPath
.appendPath(root
);
1952 const String8
rootStr(root
);
1954 if (remain
.length() == 0) {
1955 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1957 group
= dir
->getFiles().valueAt(i
);
1959 group
= new AaptGroup(rootStr
, filePath
);
1960 status_t res
= dir
->addFile(rootStr
, group
);
1961 if (res
!= NO_ERROR
) {
1965 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1966 status_t res
= group
->addFile(file
);
1967 if (res
!= NO_ERROR
) {
1973 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1975 dir
= dir
->getDirs().valueAt(i
);
1977 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1978 status_t res
= dir
->addDir(rootStr
, subdir
);
1979 if (res
!= NO_ERROR
) {
1987 mGroupEntries
.add(entry
);
1988 if (outGroup
) *outGroup
= group
;
1992 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1993 const sp
<AaptFile
>& file
, const String8
& resType
)
1995 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1996 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1997 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1998 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
2001 subdir
->addFile(leafName
, grr
);
2005 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
2010 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
2011 const size_t dirCount
=resDirs
.size();
2012 sp
<AaptAssets
> current
= this;
2014 const int N
= bundle
->getFileSpecCount();
2017 * If a package manifest was specified, include that first.
2019 if (bundle
->getAndroidManifestFile() != NULL
) {
2020 // place at root of zip.
2021 String8
srcFile(bundle
->getAndroidManifestFile());
2022 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
2028 * If a directory of custom assets was supplied, slurp 'em up.
2030 if (bundle
->getAssetSourceDir()) {
2031 const char* assetDir
= bundle
->getAssetSourceDir();
2033 FileType type
= getFileType(assetDir
);
2034 if (type
== kFileTypeNonexistent
) {
2035 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
2036 return UNKNOWN_ERROR
;
2038 if (type
!= kFileTypeDirectory
) {
2039 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2040 return UNKNOWN_ERROR
;
2043 String8
assetRoot(assetDir
);
2044 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
2045 AaptGroupEntry group
;
2046 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
2047 String8(), mFullAssetPaths
);
2053 mGroupEntries
.add(group
);
2055 totalCount
+= count
;
2057 if (bundle
->getVerbose())
2058 printf("Found %d custom asset file%s in %s\n",
2059 count
, (count
==1) ? "" : "s", assetDir
);
2063 * If a directory of resource-specific assets was supplied, slurp 'em up.
2065 for (size_t i
=0; i
<dirCount
; i
++) {
2066 const char *res
= resDirs
[i
];
2068 type
= getFileType(res
);
2069 if (type
== kFileTypeNonexistent
) {
2070 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
2071 return UNKNOWN_ERROR
;
2073 if (type
== kFileTypeDirectory
) {
2075 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
2076 current
->setOverlay(nextOverlay
);
2077 current
= nextOverlay
;
2078 current
->setFullResPaths(mFullResPaths
);
2080 count
= current
->slurpResourceTree(bundle
, String8(res
));
2086 totalCount
+= count
;
2089 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
2090 return UNKNOWN_ERROR
;
2096 * Now do any additional raw files.
2098 for (int arg
=0; arg
<N
; arg
++) {
2099 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
2101 FileType type
= getFileType(assetDir
);
2102 if (type
== kFileTypeNonexistent
) {
2103 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
2104 return UNKNOWN_ERROR
;
2106 if (type
!= kFileTypeDirectory
) {
2107 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2108 return UNKNOWN_ERROR
;
2111 String8
assetRoot(assetDir
);
2113 if (bundle
->getVerbose())
2114 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
2117 * Do a recursive traversal of subdir tree. We don't make any
2118 * guarantees about ordering, so we're okay with an inorder search
2119 * using whatever order the OS happens to hand back to us.
2121 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
2123 /* failure; report error and remove archive */
2127 totalCount
+= count
;
2129 if (bundle
->getVerbose())
2130 printf("Found %d asset file%s in %s\n",
2131 count
, (count
==1) ? "" : "s", assetDir
);
2135 if (count
!= NO_ERROR
) {
2140 count
= filter(bundle
);
2141 if (count
!= NO_ERROR
) {
2150 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
2151 const AaptGroupEntry
& kind
,
2152 const String8
& resType
,
2153 sp
<FilePathStore
>& fullResPaths
)
2155 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
2157 mGroupEntries
.add(kind
);
2163 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
2167 DIR* dir
= opendir(srcDir
.string());
2169 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
2170 return UNKNOWN_ERROR
;
2176 * Run through the directory, looking for dirs that match the
2180 struct dirent
* entry
= readdir(dir
);
2181 if (entry
== NULL
) {
2185 if (isHidden(srcDir
.string(), entry
->d_name
)) {
2189 String8
subdirName(srcDir
);
2190 subdirName
.appendPath(entry
->d_name
);
2192 AaptGroupEntry group
;
2194 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
2196 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2202 if (bundle
->getMaxResVersion() != NULL
&& group
.getVersionString().length() != 0) {
2203 int maxResInt
= atoi(bundle
->getMaxResVersion());
2204 const char *verString
= group
.getVersionString().string();
2205 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2206 if (dirVersionInt
> maxResInt
) {
2207 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2212 FileType type
= getFileType(subdirName
.string());
2214 if (type
== kFileTypeDirectory
) {
2215 sp
<AaptDir
> dir
= makeDir(resType
);
2216 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2217 resType
, mFullResPaths
);
2223 mGroupEntries
.add(group
);
2227 // Only add this directory if we don't already have a resource dir
2228 // for the current type. This ensures that we only add the dir once
2230 sp
<AaptDir
> rdir
= resDir(resType
);
2235 if (bundle
->getVerbose()) {
2236 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2252 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2255 SortedVector
<AaptGroupEntry
> entries
;
2257 ZipFile
* zip
= new ZipFile
;
2258 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2259 if (err
!= NO_ERROR
) {
2260 fprintf(stderr
, "error opening zip file %s\n", filename
);
2266 const int N
= zip
->getNumEntries();
2267 for (int i
=0; i
<N
; i
++) {
2268 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2269 if (entry
->getDeleted()) {
2273 String8
entryName(entry
->getFileName());
2275 String8 dirName
= entryName
.getPathDir();
2276 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2279 AaptGroupEntry kind
;
2282 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2283 // these are the resources, pull their type out of the directory name
2284 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2286 // these are untyped and don't have an AaptGroupEntry
2288 if (entries
.indexOf(kind
) < 0) {
2290 mGroupEntries
.add(kind
);
2293 // use the one from the zip file if they both exist.
2294 dir
->removeFile(entryName
.getPathLeaf());
2296 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2297 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2298 if (err
!= NO_ERROR
) {
2299 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2303 file
->setCompressionMethod(entry
->getCompressionMethod());
2306 if (entryName
== "AndroidManifest.xml") {
2307 printf("AndroidManifest.xml\n");
2309 printf("\n\nfile: %s\n", entryName
.string());
2312 size_t len
= entry
->getUncompressedLen();
2313 void* data
= zip
->uncompress(entry
);
2314 void* buf
= file
->editData(len
);
2315 memcpy(buf
, data
, len
);
2319 const unsigned char* p
= (unsigned char*)data
;
2320 const unsigned char* end
= p
+len
;
2322 for (int i
=0; i
<32 && p
< end
; i
++) {
2323 printf("0x%03x ", i
*0x10 + OFF
);
2324 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2325 printf(" %02x", *p
);
2342 status_t
AaptAssets::filter(Bundle
* bundle
)
2344 ResourceFilter reqFilter
;
2345 status_t err
= reqFilter
.parse(bundle
->getConfigurations());
2346 if (err
!= NO_ERROR
) {
2350 ResourceFilter prefFilter
;
2351 err
= prefFilter
.parse(bundle
->getPreferredConfigurations());
2352 if (err
!= NO_ERROR
) {
2356 if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) {
2360 if (bundle
->getVerbose()) {
2361 if (!reqFilter
.isEmpty()) {
2362 printf("Applying required filter: %s\n",
2363 bundle
->getConfigurations());
2365 if (!prefFilter
.isEmpty()) {
2366 printf("Applying preferred filter: %s\n",
2367 bundle
->getPreferredConfigurations());
2371 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2372 const size_t ND
= resdirs
.size();
2373 for (size_t i
=0; i
<ND
; i
++) {
2374 const sp
<AaptDir
>& dir
= resdirs
.itemAt(i
);
2375 if (dir
->getLeaf() == kValuesDir
) {
2376 // The "value" dir is special since a single file defines
2377 // multiple resources, so we can not do filtering on the
2378 // files themselves.
2381 if (dir
->getLeaf() == kMipmapDir
) {
2382 // We also skip the "mipmap" directory, since the point of this
2383 // is to include all densities without stripping. If you put
2384 // other configurations in here as well they won't be stripped
2385 // either... So don't do that. Seriously. What is wrong with you?
2389 const size_t NG
= dir
->getFiles().size();
2390 for (size_t j
=0; j
<NG
; j
++) {
2391 sp
<AaptGroup
> grp
= dir
->getFiles().valueAt(j
);
2393 // First remove any configurations we know we don't need.
2394 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2395 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2396 if (k
== 0 && grp
->getFiles().size() == 1) {
2397 // If this is the only file left, we need to keep it.
2398 // Otherwise the resource IDs we are using will be inconsistent
2399 // with what we get when not stripping. Sucky, but at least
2400 // for now we can rely on the back-end doing another filtering
2401 // pass to take this out and leave us with this resource name
2402 // containing no entries.
2405 if (file
->getPath().getPathExtension() == ".xml") {
2406 // We can't remove .xml files at this point, because when
2407 // we parse them they may add identifier resources, so
2408 // removing them can cause our resource identifiers to
2409 // become inconsistent.
2412 const ResTable_config
& config(file
->getGroupEntry().toParams());
2413 if (!reqFilter
.match(config
)) {
2414 if (bundle
->getVerbose()) {
2415 printf("Pruning unneeded resource: %s\n",
2416 file
->getPrintableSource().string());
2423 // Quick check: no preferred filters, nothing more to do.
2424 if (prefFilter
.isEmpty()) {
2428 // Now deal with preferred configurations.
2429 for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) {
2430 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2431 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2432 if (k
== 0 && grp
->getFiles().size() == 1) {
2433 // If this is the only file left, we need to keep it.
2434 // Otherwise the resource IDs we are using will be inconsistent
2435 // with what we get when not stripping. Sucky, but at least
2436 // for now we can rely on the back-end doing another filtering
2437 // pass to take this out and leave us with this resource name
2438 // containing no entries.
2441 if (file
->getPath().getPathExtension() == ".xml") {
2442 // We can't remove .xml files at this point, because when
2443 // we parse them they may add identifier resources, so
2444 // removing them can cause our resource identifiers to
2445 // become inconsistent.
2448 const ResTable_config
& config(file
->getGroupEntry().toParams());
2449 if (!prefFilter
.match(axis
, config
)) {
2450 // This is a resource we would prefer not to have. Check
2451 // to see if have a similar variation that we would like
2452 // to have and, if so, we can drop it.
2453 for (size_t m
=0; m
<grp
->getFiles().size(); m
++) {
2454 if (m
== k
) continue;
2455 sp
<AaptFile
> mfile
= grp
->getFiles().valueAt(m
);
2456 const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams());
2457 if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) {
2458 if (prefFilter
.match(axis
, mconfig
)) {
2459 if (bundle
->getVerbose()) {
2460 printf("Pruning unneeded resource: %s\n",
2461 file
->getPrintableSource().string());
2478 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2480 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2482 sym
= new AaptSymbols();
2483 mSymbols
.add(name
, sym
);
2488 sp
<AaptSymbols
> AaptAssets::getJavaSymbolsFor(const String8
& name
)
2490 sp
<AaptSymbols
> sym
= mJavaSymbols
.valueFor(name
);
2492 sym
= new AaptSymbols();
2493 mJavaSymbols
.add(name
, sym
);
2498 status_t
AaptAssets::applyJavaSymbols()
2500 size_t N
= mJavaSymbols
.size();
2501 for (size_t i
=0; i
<N
; i
++) {
2502 const String8
& name
= mJavaSymbols
.keyAt(i
);
2503 const sp
<AaptSymbols
>& symbols
= mJavaSymbols
.valueAt(i
);
2504 ssize_t pos
= mSymbols
.indexOfKey(name
);
2507 pos
.error("Java symbol dir %s not defined\n", name
.string());
2508 return UNKNOWN_ERROR
;
2510 //printf("**** applying java symbols in dir %s\n", name.string());
2511 status_t err
= mSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
2512 if (err
!= NO_ERROR
) {
2520 bool AaptAssets::isJavaSymbol(const AaptSymbolEntry
& sym
, bool includePrivate
) const {
2521 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2522 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2523 // sym.isJavaSymbol ? 1 : 0);
2524 if (!mHavePrivateSymbols
) return true;
2525 if (sym
.isPublic
) return true;
2526 if (includePrivate
&& sym
.isJavaSymbol
) return true;
2530 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2532 if (!mHaveIncludedAssets
) {
2533 // Add in all includes.
2534 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2535 const size_t N
=incl
.size();
2536 for (size_t i
=0; i
<N
; i
++) {
2537 if (bundle
->getVerbose())
2538 printf("Including resources from package: %s\n", incl
[i
]);
2539 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2540 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2542 return UNKNOWN_ERROR
;
2545 mHaveIncludedAssets
= true;
2551 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2553 const ResTable
& res
= getIncludedResources();
2555 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2558 const ResTable
& AaptAssets::getIncludedResources() const
2560 return mIncludedAssets
.getResources(false);
2563 void AaptAssets::print(const String8
& prefix
) const
2565 String8
innerPrefix(prefix
);
2566 innerPrefix
.append(" ");
2567 String8
innerInnerPrefix(innerPrefix
);
2568 innerInnerPrefix
.append(" ");
2569 printf("%sConfigurations:\n", prefix
.string());
2570 const size_t N
=mGroupEntries
.size();
2571 for (size_t i
=0; i
<N
; i
++) {
2572 String8 cname
= mGroupEntries
.itemAt(i
).toDirName(String8());
2573 printf("%s %s\n", prefix
.string(),
2574 cname
!= "" ? cname
.string() : "(default)");
2577 printf("\n%sFiles:\n", prefix
.string());
2578 AaptDir::print(innerPrefix
);
2580 printf("\n%sResource Dirs:\n", prefix
.string());
2581 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2582 const size_t NR
= resdirs
.size();
2583 for (size_t i
=0; i
<NR
; i
++) {
2584 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2585 printf("%s Type %s\n", prefix
.string(), d
->getLeaf().string());
2586 d
->print(innerInnerPrefix
);
2590 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const
2592 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2593 const size_t N
= resdirs
.size();
2594 for (size_t i
=0; i
<N
; i
++) {
2595 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2596 if (d
->getLeaf() == name
) {
2604 valid_symbol_name(const String8
& symbol
)
2606 static char const * const KEYWORDS
[] = {
2607 "abstract", "assert", "boolean", "break",
2608 "byte", "case", "catch", "char", "class", "const", "continue",
2609 "default", "do", "double", "else", "enum", "extends", "final",
2610 "finally", "float", "for", "goto", "if", "implements", "import",
2611 "instanceof", "int", "interface", "long", "native", "new", "package",
2612 "private", "protected", "public", "return", "short", "static",
2613 "strictfp", "super", "switch", "synchronized", "this", "throw",
2614 "throws", "transient", "try", "void", "volatile", "while",
2615 "true", "false", "null",
2618 const char*const* k
= KEYWORDS
;
2619 const char*const s
= symbol
.string();
2621 if (0 == strcmp(s
, *k
)) {