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 static bool isHidden(const char *root
, const char *path
)
61 const char *ext
= NULL
;
62 const char *type
= NULL
;
64 // Skip all hidden files.
66 // Skip ., .. and .svn but don't chatter about it.
67 if (strcmp(path
, ".") == 0
68 || strcmp(path
, "..") == 0
69 || strcmp(path
, ".svn") == 0) {
73 } else if (path
[0] == '_') {
74 // skip directories starting with _ (don't chatter about it)
75 String8
subdirName(root
);
76 subdirName
.appendPath(path
);
77 if (getFileType(subdirName
.string()) == kFileTypeDirectory
) {
80 } else if (strcmp(path
, "CVS") == 0) {
81 // Skip CVS but don't chatter about it.
83 } else if (strcasecmp(path
, "thumbs.db") == 0
84 || strcasecmp(path
, "picasa.ini") == 0) {
85 // Skip suspected image indexes files.
87 } else if (path
[strlen(path
)-1] == '~') {
88 // Skip suspected emacs backup files.
90 } else if ((ext
= strrchr(path
, '.')) != NULL
&& strcmp(ext
, ".scc") == 0) {
91 // Skip VisualSourceSafe files and don't chatter about it
94 // Let everything else through.
98 /* If we get this far, "type" should be set and the file
101 String8
subdirName(root
);
102 subdirName
.appendPath(path
);
103 fprintf(stderr
, " (skipping %s %s '%s')\n", type
,
104 getFileType(subdirName
.string())==kFileTypeDirectory
? "dir":"file",
105 subdirName
.string());
110 // =========================================================================
111 // =========================================================================
112 // =========================================================================
115 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
)
117 ResTable_config config
;
120 if (getMccName(part
.string(), &config
)) {
127 if (getMncName(part
.string(), &config
)) {
134 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
135 *axis
= AXIS_LANGUAGE
;
136 *value
= part
[1] << 8 | part
[0];
140 // locale - language_REGION
141 if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1])
142 && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) {
143 *axis
= AXIS_LANGUAGE
;
144 *value
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]);
148 // smallest screen dp width
149 if (getSmallestScreenWidthDpName(part
.string(), &config
)) {
150 *axis
= AXIS_SMALLESTSCREENWIDTHDP
;
151 *value
= config
.smallestScreenWidthDp
;
156 if (getScreenWidthDpName(part
.string(), &config
)) {
157 *axis
= AXIS_SCREENWIDTHDP
;
158 *value
= config
.screenWidthDp
;
163 if (getScreenHeightDpName(part
.string(), &config
)) {
164 *axis
= AXIS_SCREENHEIGHTDP
;
165 *value
= config
.screenHeightDp
;
169 // screen layout size
170 if (getScreenLayoutSizeName(part
.string(), &config
)) {
171 *axis
= AXIS_SCREENLAYOUTSIZE
;
172 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
176 // screen layout long
177 if (getScreenLayoutLongName(part
.string(), &config
)) {
178 *axis
= AXIS_SCREENLAYOUTLONG
;
179 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
184 if (getOrientationName(part
.string(), &config
)) {
185 *axis
= AXIS_ORIENTATION
;
186 *value
= config
.orientation
;
191 if (getUiModeTypeName(part
.string(), &config
)) {
192 *axis
= AXIS_UIMODETYPE
;
193 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
198 if (getUiModeNightName(part
.string(), &config
)) {
199 *axis
= AXIS_UIMODENIGHT
;
200 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
205 if (getDensityName(part
.string(), &config
)) {
206 *axis
= AXIS_DENSITY
;
207 *value
= config
.density
;
212 if (getTouchscreenName(part
.string(), &config
)) {
213 *axis
= AXIS_TOUCHSCREEN
;
214 *value
= config
.touchscreen
;
219 if (getKeysHiddenName(part
.string(), &config
)) {
220 *axis
= AXIS_KEYSHIDDEN
;
221 *value
= config
.inputFlags
;
226 if (getKeyboardName(part
.string(), &config
)) {
227 *axis
= AXIS_KEYBOARD
;
228 *value
= config
.keyboard
;
233 if (getNavHiddenName(part
.string(), &config
)) {
234 *axis
= AXIS_NAVHIDDEN
;
235 *value
= config
.inputFlags
;
240 if (getNavigationName(part
.string(), &config
)) {
241 *axis
= AXIS_NAVIGATION
;
242 *value
= config
.navigation
;
247 if (getScreenSizeName(part
.string(), &config
)) {
248 *axis
= AXIS_SCREENSIZE
;
249 *value
= config
.screenSize
;
254 if (getVersionName(part
.string(), &config
)) {
255 *axis
= AXIS_VERSION
;
256 *value
= config
.version
;
264 AaptGroupEntry::getConfigValueForAxis(const ResTable_config
& config
, int axis
)
272 return (((uint32_t)config
.country
[1]) << 24) | (((uint32_t)config
.country
[0]) << 16)
273 | (((uint32_t)config
.language
[1]) << 8) | (config
.language
[0]);
274 case AXIS_SCREENLAYOUTSIZE
:
275 return config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
;
276 case AXIS_ORIENTATION
:
277 return config
.orientation
;
278 case AXIS_UIMODETYPE
:
279 return (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
280 case AXIS_UIMODENIGHT
:
281 return (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
283 return config
.density
;
284 case AXIS_TOUCHSCREEN
:
285 return config
.touchscreen
;
286 case AXIS_KEYSHIDDEN
:
287 return config
.inputFlags
;
289 return config
.keyboard
;
290 case AXIS_NAVIGATION
:
291 return config
.navigation
;
292 case AXIS_SCREENSIZE
:
293 return config
.screenSize
;
294 case AXIS_SMALLESTSCREENWIDTHDP
:
295 return config
.smallestScreenWidthDp
;
296 case AXIS_SCREENWIDTHDP
:
297 return config
.screenWidthDp
;
298 case AXIS_SCREENHEIGHTDP
:
299 return config
.screenHeightDp
;
301 return config
.version
;
307 AaptGroupEntry::configSameExcept(const ResTable_config
& config
,
308 const ResTable_config
& otherConfig
, int axis
)
310 for (int i
=AXIS_START
; i
<=AXIS_END
; i
++) {
314 if (getConfigValueForAxis(config
, i
) != getConfigValueForAxis(otherConfig
, i
)) {
322 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
324 mParamsChanged
= true;
326 Vector
<String8
> parts
;
328 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
329 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
;
330 String8 uiModeType
, uiModeNight
, smallestwidthdp
, widthdp
, heightdp
;
334 while (NULL
!= (q
= strchr(p
, '-'))) {
338 //printf("part: %s\n", parts[parts.size()-1].string());
344 //printf("part: %s\n", parts[parts.size()-1].string());
346 const int N
= parts
.size();
348 String8 part
= parts
[index
];
351 if (!isValidResourceType(part
)) {
363 if (getMccName(part
.string())) {
372 //printf("not mcc: %s\n", part.string());
376 if (getMncName(part
.string())) {
385 //printf("not mcc: %s\n", part.string());
389 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
398 //printf("not language: %s\n", part.string());
403 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
406 loc
+= part
.string() + 1;
414 //printf("not region: %s\n", part.string());
417 if (getSmallestScreenWidthDpName(part
.string())) {
418 smallestwidthdp
= part
;
426 //printf("not smallest screen width dp: %s\n", part.string());
429 if (getScreenWidthDpName(part
.string())) {
438 //printf("not screen width dp: %s\n", part.string());
441 if (getScreenHeightDpName(part
.string())) {
450 //printf("not screen height dp: %s\n", part.string());
453 if (getScreenLayoutSizeName(part
.string())) {
462 //printf("not screen layout size: %s\n", part.string());
465 if (getScreenLayoutLongName(part
.string())) {
474 //printf("not screen layout long: %s\n", part.string());
478 if (getOrientationName(part
.string())) {
487 //printf("not orientation: %s\n", part.string());
491 if (getUiModeTypeName(part
.string())) {
500 //printf("not ui mode type: %s\n", part.string());
504 if (getUiModeNightName(part
.string())) {
513 //printf("not ui mode night: %s\n", part.string());
517 if (getDensityName(part
.string())) {
526 //printf("not density: %s\n", part.string());
530 if (getTouchscreenName(part
.string())) {
539 //printf("not touchscreen: %s\n", part.string());
543 if (getKeysHiddenName(part
.string())) {
552 //printf("not keysHidden: %s\n", part.string());
556 if (getKeyboardName(part
.string())) {
565 //printf("not keyboard: %s\n", part.string());
569 if (getNavHiddenName(part
.string())) {
578 //printf("not navHidden: %s\n", part.string());
581 if (getNavigationName(part
.string())) {
590 //printf("not navigation: %s\n", part.string());
593 if (getScreenSizeName(part
.string())) {
602 //printf("not screen size: %s\n", part.string());
605 if (getVersionName(part
.string())) {
614 //printf("not version: %s\n", part.string());
617 // if there are extra parts, it doesn't match
624 this->screenLayoutSize
= layoutsize
;
625 this->screenLayoutLong
= layoutlong
;
626 this->smallestScreenWidthDp
= smallestwidthdp
;
627 this->screenWidthDp
= widthdp
;
628 this->screenHeightDp
= heightdp
;
629 this->orientation
= orient
;
630 this->uiModeType
= uiModeType
;
631 this->uiModeNight
= uiModeNight
;
633 this->touchscreen
= touch
;
634 this->keysHidden
= keysHidden
;
635 this->keyboard
= key
;
636 this->navHidden
= navHidden
;
637 this->navigation
= nav
;
638 this->screenSize
= size
;
639 this->version
= vers
;
641 // what is this anyway?
648 AaptGroupEntry::toString() const
650 String8 s
= this->mcc
;
656 s
+= smallestScreenWidthDp
;
662 s
+= screenLayoutSize
;
664 s
+= screenLayoutLong
;
666 s
+= this->orientation
;
691 AaptGroupEntry::toDirName(const String8
& resType
) const
694 if (this->mcc
!= "") {
695 if (s
.length() > 0) {
700 if (this->mnc
!= "") {
701 if (s
.length() > 0) {
706 if (this->locale
!= "") {
707 if (s
.length() > 0) {
712 if (this->smallestScreenWidthDp
!= "") {
713 if (s
.length() > 0) {
716 s
+= smallestScreenWidthDp
;
718 if (this->screenWidthDp
!= "") {
719 if (s
.length() > 0) {
724 if (this->screenHeightDp
!= "") {
725 if (s
.length() > 0) {
730 if (this->screenLayoutSize
!= "") {
731 if (s
.length() > 0) {
734 s
+= screenLayoutSize
;
736 if (this->screenLayoutLong
!= "") {
737 if (s
.length() > 0) {
740 s
+= screenLayoutLong
;
742 if (this->orientation
!= "") {
743 if (s
.length() > 0) {
748 if (this->uiModeType
!= "") {
749 if (s
.length() > 0) {
754 if (this->uiModeNight
!= "") {
755 if (s
.length() > 0) {
760 if (this->density
!= "") {
761 if (s
.length() > 0) {
766 if (this->touchscreen
!= "") {
767 if (s
.length() > 0) {
772 if (this->keysHidden
!= "") {
773 if (s
.length() > 0) {
778 if (this->keyboard
!= "") {
779 if (s
.length() > 0) {
784 if (this->navHidden
!= "") {
785 if (s
.length() > 0) {
790 if (this->navigation
!= "") {
791 if (s
.length() > 0) {
796 if (this->screenSize
!= "") {
797 if (s
.length() > 0) {
802 if (this->version
!= "") {
803 if (s
.length() > 0) {
812 bool AaptGroupEntry::getMccName(const char* name
,
813 ResTable_config
* out
)
815 if (strcmp(name
, kWildcardName
) == 0) {
816 if (out
) out
->mcc
= 0;
819 const char* c
= name
;
820 if (tolower(*c
) != 'm') return false;
822 if (tolower(*c
) != 'c') return false;
824 if (tolower(*c
) != 'c') return false;
829 while (*c
>= '0' && *c
<= '9') {
832 if (*c
!= 0) return false;
833 if (c
-val
!= 3) return false;
837 if (out
) out
->mcc
= d
;
844 bool AaptGroupEntry::getMncName(const char* name
,
845 ResTable_config
* out
)
847 if (strcmp(name
, kWildcardName
) == 0) {
848 if (out
) out
->mcc
= 0;
851 const char* c
= name
;
852 if (tolower(*c
) != 'm') return false;
854 if (tolower(*c
) != 'n') return false;
856 if (tolower(*c
) != 'c') return false;
861 while (*c
>= '0' && *c
<= '9') {
864 if (*c
!= 0) return false;
865 if (c
-val
== 0 || c
-val
> 3) return false;
868 out
->mnc
= atoi(val
);
875 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
878 * TODO: Should insist that the first two letters are lower case, and the
879 * second two are upper.
881 bool AaptGroupEntry::getLocaleName(const char* fileName
,
882 ResTable_config
* out
)
884 if (strcmp(fileName
, kWildcardName
) == 0
885 || strcmp(fileName
, kDefaultLocale
) == 0) {
887 out
->language
[0] = 0;
888 out
->language
[1] = 0;
895 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
897 out
->language
[0] = fileName
[0];
898 out
->language
[1] = fileName
[1];
905 if (strlen(fileName
) == 5 &&
906 isalpha(fileName
[0]) &&
907 isalpha(fileName
[1]) &&
908 fileName
[2] == '-' &&
909 isalpha(fileName
[3]) &&
910 isalpha(fileName
[4])) {
912 out
->language
[0] = fileName
[0];
913 out
->language
[1] = fileName
[1];
914 out
->country
[0] = fileName
[3];
915 out
->country
[1] = fileName
[4];
923 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
924 ResTable_config
* out
)
926 if (strcmp(name
, kWildcardName
) == 0) {
927 if (out
) out
->screenLayout
=
928 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
929 | ResTable_config::SCREENSIZE_ANY
;
931 } else if (strcmp(name
, "small") == 0) {
932 if (out
) out
->screenLayout
=
933 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
934 | ResTable_config::SCREENSIZE_SMALL
;
936 } else if (strcmp(name
, "normal") == 0) {
937 if (out
) out
->screenLayout
=
938 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
939 | ResTable_config::SCREENSIZE_NORMAL
;
941 } else if (strcmp(name
, "large") == 0) {
942 if (out
) out
->screenLayout
=
943 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
944 | ResTable_config::SCREENSIZE_LARGE
;
946 } else if (strcmp(name
, "xlarge") == 0) {
947 if (out
) out
->screenLayout
=
948 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
949 | ResTable_config::SCREENSIZE_XLARGE
;
956 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
957 ResTable_config
* out
)
959 if (strcmp(name
, kWildcardName
) == 0) {
960 if (out
) out
->screenLayout
=
961 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
962 | ResTable_config::SCREENLONG_ANY
;
964 } else if (strcmp(name
, "long") == 0) {
965 if (out
) out
->screenLayout
=
966 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
967 | ResTable_config::SCREENLONG_YES
;
969 } else if (strcmp(name
, "notlong") == 0) {
970 if (out
) out
->screenLayout
=
971 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
972 | ResTable_config::SCREENLONG_NO
;
979 bool AaptGroupEntry::getOrientationName(const char* name
,
980 ResTable_config
* out
)
982 if (strcmp(name
, kWildcardName
) == 0) {
983 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
985 } else if (strcmp(name
, "port") == 0) {
986 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
988 } else if (strcmp(name
, "land") == 0) {
989 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
991 } else if (strcmp(name
, "square") == 0) {
992 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
999 bool AaptGroupEntry::getUiModeTypeName(const char* name
,
1000 ResTable_config
* out
)
1002 if (strcmp(name
, kWildcardName
) == 0) {
1003 if (out
) out
->uiMode
=
1004 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1005 | ResTable_config::UI_MODE_TYPE_ANY
;
1007 } else if (strcmp(name
, "desk") == 0) {
1008 if (out
) out
->uiMode
=
1009 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1010 | ResTable_config::UI_MODE_TYPE_DESK
;
1012 } else if (strcmp(name
, "car") == 0) {
1013 if (out
) out
->uiMode
=
1014 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1015 | ResTable_config::UI_MODE_TYPE_CAR
;
1017 } else if (strcmp(name
, "television") == 0) {
1018 if (out
) out
->uiMode
=
1019 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1020 | ResTable_config::UI_MODE_TYPE_TELEVISION
;
1027 bool AaptGroupEntry::getUiModeNightName(const char* name
,
1028 ResTable_config
* out
)
1030 if (strcmp(name
, kWildcardName
) == 0) {
1031 if (out
) out
->uiMode
=
1032 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1033 | ResTable_config::UI_MODE_NIGHT_ANY
;
1035 } else if (strcmp(name
, "night") == 0) {
1036 if (out
) out
->uiMode
=
1037 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1038 | ResTable_config::UI_MODE_NIGHT_YES
;
1040 } else if (strcmp(name
, "notnight") == 0) {
1041 if (out
) out
->uiMode
=
1042 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1043 | ResTable_config::UI_MODE_NIGHT_NO
;
1050 bool AaptGroupEntry::getDensityName(const char* name
,
1051 ResTable_config
* out
)
1053 if (strcmp(name
, kWildcardName
) == 0) {
1054 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
1058 if (strcmp(name
, "nodpi") == 0) {
1059 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
1063 if (strcmp(name
, "ldpi") == 0) {
1064 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
1068 if (strcmp(name
, "mdpi") == 0) {
1069 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
1073 if (strcmp(name
, "tvdpi") == 0) {
1074 if (out
) out
->density
= ResTable_config::DENSITY_TV
;
1078 if (strcmp(name
, "hdpi") == 0) {
1079 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
1083 if (strcmp(name
, "xhdpi") == 0) {
1084 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
*2;
1088 char* c
= (char*)name
;
1089 while (*c
>= '0' && *c
<= '9') {
1093 // check that we have 'dpi' after the last digit.
1094 if (toupper(c
[0]) != 'D' ||
1095 toupper(c
[1]) != 'P' ||
1096 toupper(c
[2]) != 'I' ||
1101 // temporarily replace the first letter with \0 to
1110 if (out
) out
->density
= d
;
1117 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1118 ResTable_config
* out
)
1120 if (strcmp(name
, kWildcardName
) == 0) {
1121 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1123 } else if (strcmp(name
, "notouch") == 0) {
1124 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1126 } else if (strcmp(name
, "stylus") == 0) {
1127 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1129 } else if (strcmp(name
, "finger") == 0) {
1130 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1137 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1138 ResTable_config
* out
)
1142 if (strcmp(name
, kWildcardName
) == 0) {
1143 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1144 value
= ResTable_config::KEYSHIDDEN_ANY
;
1145 } else if (strcmp(name
, "keysexposed") == 0) {
1146 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1147 value
= ResTable_config::KEYSHIDDEN_NO
;
1148 } else if (strcmp(name
, "keyshidden") == 0) {
1149 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1150 value
= ResTable_config::KEYSHIDDEN_YES
;
1151 } else if (strcmp(name
, "keyssoft") == 0) {
1152 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1153 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1157 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1164 bool AaptGroupEntry::getKeyboardName(const char* name
,
1165 ResTable_config
* out
)
1167 if (strcmp(name
, kWildcardName
) == 0) {
1168 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1170 } else if (strcmp(name
, "nokeys") == 0) {
1171 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1173 } else if (strcmp(name
, "qwerty") == 0) {
1174 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1176 } else if (strcmp(name
, "12key") == 0) {
1177 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1184 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1185 ResTable_config
* out
)
1189 if (strcmp(name
, kWildcardName
) == 0) {
1190 mask
= ResTable_config::MASK_NAVHIDDEN
;
1191 value
= ResTable_config::NAVHIDDEN_ANY
;
1192 } else if (strcmp(name
, "navexposed") == 0) {
1193 mask
= ResTable_config::MASK_NAVHIDDEN
;
1194 value
= ResTable_config::NAVHIDDEN_NO
;
1195 } else if (strcmp(name
, "navhidden") == 0) {
1196 mask
= ResTable_config::MASK_NAVHIDDEN
;
1197 value
= ResTable_config::NAVHIDDEN_YES
;
1201 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1208 bool AaptGroupEntry::getNavigationName(const char* name
,
1209 ResTable_config
* out
)
1211 if (strcmp(name
, kWildcardName
) == 0) {
1212 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1214 } else if (strcmp(name
, "nonav") == 0) {
1215 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1217 } else if (strcmp(name
, "dpad") == 0) {
1218 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1220 } else if (strcmp(name
, "trackball") == 0) {
1221 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1223 } else if (strcmp(name
, "wheel") == 0) {
1224 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1231 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1233 if (strcmp(name
, kWildcardName
) == 0) {
1235 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1236 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1241 const char* x
= name
;
1242 while (*x
>= '0' && *x
<= '9') x
++;
1243 if (x
== name
|| *x
!= 'x') return false;
1244 String8
xName(name
, x
-name
);
1248 while (*y
>= '0' && *y
<= '9') y
++;
1249 if (y
== name
|| *y
!= 0) return false;
1250 String8
yName(x
, y
-x
);
1252 uint16_t w
= (uint16_t)atoi(xName
.string());
1253 uint16_t h
= (uint16_t)atoi(yName
.string());
1259 out
->screenWidth
= w
;
1260 out
->screenHeight
= h
;
1266 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1268 if (strcmp(name
, kWildcardName
) == 0) {
1270 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1275 if (*name
!= 's') return false;
1277 if (*name
!= 'w') return false;
1279 const char* x
= name
;
1280 while (*x
>= '0' && *x
<= '9') x
++;
1281 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1282 String8
xName(name
, x
-name
);
1285 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1291 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1293 if (strcmp(name
, kWildcardName
) == 0) {
1295 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1300 if (*name
!= 'w') return false;
1302 const char* x
= name
;
1303 while (*x
>= '0' && *x
<= '9') x
++;
1304 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1305 String8
xName(name
, x
-name
);
1308 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1314 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1316 if (strcmp(name
, kWildcardName
) == 0) {
1318 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1323 if (*name
!= 'h') return false;
1325 const char* x
= name
;
1326 while (*x
>= '0' && *x
<= '9') x
++;
1327 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1328 String8
xName(name
, x
-name
);
1331 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1337 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1339 if (strcmp(name
, kWildcardName
) == 0) {
1341 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1342 out
->minorVersion
= out
->MINORVERSION_ANY
;
1352 const char* s
= name
;
1353 while (*s
>= '0' && *s
<= '9') s
++;
1354 if (s
== name
|| *s
!= 0) return false;
1355 String8
sdkName(name
, s
-name
);
1358 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1359 out
->minorVersion
= 0;
1365 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1367 int v
= mcc
.compare(o
.mcc
);
1368 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1369 if (v
== 0) v
= locale
.compare(o
.locale
);
1370 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1371 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1372 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1373 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1374 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1375 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1376 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1377 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1378 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1379 if (v
== 0) v
= density
.compare(o
.density
);
1380 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1381 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1382 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1383 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1384 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1385 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1386 if (v
== 0) v
= version
.compare(o
.version
);
1390 const ResTable_config
& AaptGroupEntry::toParams() const
1392 if (!mParamsChanged
) {
1396 mParamsChanged
= false;
1397 ResTable_config
& params(mParams
);
1398 memset(¶ms
, 0, sizeof(params
));
1399 getMccName(mcc
.string(), ¶ms
);
1400 getMncName(mnc
.string(), ¶ms
);
1401 getLocaleName(locale
.string(), ¶ms
);
1402 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1403 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1404 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1405 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1406 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1407 getOrientationName(orientation
.string(), ¶ms
);
1408 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1409 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1410 getDensityName(density
.string(), ¶ms
);
1411 getTouchscreenName(touchscreen
.string(), ¶ms
);
1412 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1413 getKeyboardName(keyboard
.string(), ¶ms
);
1414 getNavHiddenName(navHidden
.string(), ¶ms
);
1415 getNavigationName(navigation
.string(), ¶ms
);
1416 getScreenSizeName(screenSize
.string(), ¶ms
);
1417 getVersionName(version
.string(), ¶ms
);
1419 // Fix up version number based on specified parameters.
1421 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1422 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1423 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1424 minSdk
= SDK_HONEYCOMB_MR2
;
1425 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1426 != ResTable_config::UI_MODE_TYPE_ANY
1427 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1428 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1430 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1431 != ResTable_config::SCREENSIZE_ANY
1432 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1433 != ResTable_config::SCREENLONG_ANY
1434 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1438 if (minSdk
> params
.sdkVersion
) {
1439 params
.sdkVersion
= minSdk
;
1445 // =========================================================================
1446 // =========================================================================
1447 // =========================================================================
1449 void* AaptFile::editData(size_t size
)
1451 if (size
<= mBufferSize
) {
1455 size_t allocSize
= (size
*3)/2;
1456 void* buf
= realloc(mData
, allocSize
);
1462 mBufferSize
= allocSize
;
1466 void* AaptFile::editData(size_t* outSize
)
1469 *outSize
= mDataSize
;
1474 void* AaptFile::padData(size_t wordSize
)
1476 const size_t extra
= mDataSize%wordSize
;
1481 size_t initial
= mDataSize
;
1482 void* data
= editData(initial
+(wordSize
-extra
));
1484 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1489 status_t
AaptFile::writeData(const void* data
, size_t size
)
1491 size_t end
= mDataSize
;
1492 size_t total
= size
+ end
;
1493 void* buf
= editData(total
);
1495 return UNKNOWN_ERROR
;
1497 memcpy(((char*)buf
)+end
, data
, size
);
1501 void AaptFile::clearData()
1503 if (mData
!= NULL
) free(mData
);
1509 String8
AaptFile::getPrintableSource() const
1512 String8
name(mGroupEntry
.toDirName(String8()));
1513 name
.appendPath(mPath
);
1514 name
.append(" #generated");
1520 // =========================================================================
1521 // =========================================================================
1522 // =========================================================================
1524 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1526 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1527 file
->mPath
= mPath
;
1528 mFiles
.add(file
->getGroupEntry(), file
);
1533 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1534 file
->getSourceFile().string(),
1535 file
->getGroupEntry().toDirName(String8()).string(),
1536 mLeaf
.string(), mPath
.string());
1539 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1540 getPrintableSource().string());
1541 return UNKNOWN_ERROR
;
1544 void AaptGroup::removeFile(size_t index
)
1546 mFiles
.removeItemsAt(index
);
1549 void AaptGroup::print(const String8
& prefix
) const
1551 printf("%s%s\n", prefix
.string(), getPath().string());
1552 const size_t N
=mFiles
.size();
1554 for (i
=0; i
<N
; i
++) {
1555 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1556 const AaptGroupEntry
& e
= file
->getGroupEntry();
1557 if (file
->hasData()) {
1558 printf("%s Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(),
1559 (int)file
->getSize());
1561 printf("%s Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(),
1562 file
->getPrintableSource().string());
1564 //printf("%s File Group Entry: %s\n", prefix.string(),
1565 // file->getGroupEntry().toDirName(String8()).string());
1569 String8
AaptGroup::getPrintableSource() const
1571 if (mFiles
.size() > 0) {
1572 // Arbitrarily pull the first source file out of the list.
1573 return mFiles
.valueAt(0)->getPrintableSource();
1576 // Should never hit this case, but to be safe...
1581 // =========================================================================
1582 // =========================================================================
1583 // =========================================================================
1585 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1587 if (mFiles
.indexOfKey(name
) >= 0) {
1588 return ALREADY_EXISTS
;
1590 mFiles
.add(name
, file
);
1594 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1596 if (mDirs
.indexOfKey(name
) >= 0) {
1597 return ALREADY_EXISTS
;
1599 mDirs
.add(name
, dir
);
1603 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1606 String8 remain
= path
;
1608 sp
<AaptDir
> subdir
= this;
1609 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1610 subdir
= subdir
->makeDir(name
);
1613 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1615 return subdir
->mDirs
.valueAt(i
);
1617 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1618 subdir
->mDirs
.add(name
, dir
);
1622 void AaptDir::removeFile(const String8
& name
)
1624 mFiles
.removeItem(name
);
1627 void AaptDir::removeDir(const String8
& name
)
1629 mDirs
.removeItem(name
);
1632 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1634 sp
<AaptGroup
> group
;
1635 if (mFiles
.indexOfKey(leafName
) >= 0) {
1636 group
= mFiles
.valueFor(leafName
);
1638 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1639 mFiles
.add(leafName
, group
);
1642 return group
->addFile(file
);
1645 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1646 const AaptGroupEntry
& kind
, const String8
& resType
,
1647 sp
<FilePathStore
>& fullResPaths
)
1649 Vector
<String8
> fileNames
;
1653 dir
= opendir(srcDir
.string());
1655 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1656 return UNKNOWN_ERROR
;
1660 * Slurp the filenames out of the directory.
1663 struct dirent
* entry
;
1665 entry
= readdir(dir
);
1669 if (isHidden(srcDir
.string(), entry
->d_name
))
1672 String8
name(entry
->d_name
);
1673 fileNames
.add(name
);
1674 // Add fully qualified path for dependency purposes
1675 // if we're collecting them
1676 if (fullResPaths
!= NULL
) {
1677 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1686 * Stash away the files and recursively descend into subdirectories.
1688 const size_t N
= fileNames
.size();
1690 for (i
= 0; i
< N
; i
++) {
1691 String8
pathName(srcDir
);
1694 pathName
.appendPath(fileNames
[i
].string());
1695 type
= getFileType(pathName
.string());
1696 if (type
== kFileTypeDirectory
) {
1698 bool notAdded
= false;
1699 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1700 subdir
= mDirs
.valueFor(fileNames
[i
]);
1702 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1705 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1706 resType
, fullResPaths
);
1707 if (res
< NO_ERROR
) {
1710 if (res
> 0 && notAdded
) {
1711 mDirs
.add(fileNames
[i
], subdir
);
1714 } else if (type
== kFileTypeRegular
) {
1715 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1716 status_t err
= addLeafFile(fileNames
[i
], file
);
1717 if (err
!= NO_ERROR
) {
1724 if (bundle
->getVerbose())
1725 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1732 status_t
AaptDir::validate() const
1734 const size_t NF
= mFiles
.size();
1735 const size_t ND
= mDirs
.size();
1737 for (i
= 0; i
< NF
; i
++) {
1738 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1739 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1740 "Invalid filename. Unable to add.");
1741 return UNKNOWN_ERROR
;
1745 for (j
= i
+1; j
< NF
; j
++) {
1746 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1747 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1748 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1749 "File is case-insensitive equivalent to: %s",
1750 mFiles
.valueAt(j
)->getPrintableSource().string());
1751 return UNKNOWN_ERROR
;
1754 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1755 // (this is mostly caught by the "marked" stuff, below)
1758 for (j
= 0; j
< ND
; j
++) {
1759 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1760 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1761 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1762 "File conflicts with dir from: %s",
1763 mDirs
.valueAt(j
)->getPrintableSource().string());
1764 return UNKNOWN_ERROR
;
1769 for (i
= 0; i
< ND
; i
++) {
1770 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1771 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1772 "Invalid directory name, unable to add.");
1773 return UNKNOWN_ERROR
;
1777 for (j
= i
+1; j
< ND
; j
++) {
1778 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1779 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1780 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1781 "Directory is case-insensitive equivalent to: %s",
1782 mDirs
.valueAt(j
)->getPrintableSource().string());
1783 return UNKNOWN_ERROR
;
1787 status_t err
= mDirs
.valueAt(i
)->validate();
1788 if (err
!= NO_ERROR
) {
1796 void AaptDir::print(const String8
& prefix
) const
1798 const size_t ND
=getDirs().size();
1800 for (i
=0; i
<ND
; i
++) {
1801 getDirs().valueAt(i
)->print(prefix
);
1804 const size_t NF
=getFiles().size();
1805 for (i
=0; i
<NF
; i
++) {
1806 getFiles().valueAt(i
)->print(prefix
);
1810 String8
AaptDir::getPrintableSource() const
1812 if (mFiles
.size() > 0) {
1813 // Arbitrarily pull the first file out of the list as the source dir.
1814 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1816 if (mDirs
.size() > 0) {
1817 // Or arbitrarily pull the first dir out of the list as the source dir.
1818 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1821 // Should never hit this case, but to be safe...
1826 // =========================================================================
1827 // =========================================================================
1828 // =========================================================================
1830 AaptAssets::AaptAssets()
1831 : AaptDir(String8(), String8()),
1832 mChanged(false), mHaveIncludedAssets(false), mRes(NULL
)
1836 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const {
1839 return mGroupEntries
;
1842 status_t
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1845 return AaptDir::addFile(name
, file
);
1848 sp
<AaptFile
> AaptAssets::addFile(
1849 const String8
& filePath
, const AaptGroupEntry
& entry
,
1850 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1851 const String8
& resType
)
1853 sp
<AaptDir
> dir
= this;
1854 sp
<AaptGroup
> group
;
1856 String8 root
, remain(filePath
), partialPath
;
1857 while (remain
.length() > 0) {
1858 root
= remain
.walkPath(&remain
);
1859 partialPath
.appendPath(root
);
1861 const String8
rootStr(root
);
1863 if (remain
.length() == 0) {
1864 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1866 group
= dir
->getFiles().valueAt(i
);
1868 group
= new AaptGroup(rootStr
, filePath
);
1869 status_t res
= dir
->addFile(rootStr
, group
);
1870 if (res
!= NO_ERROR
) {
1874 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1875 status_t res
= group
->addFile(file
);
1876 if (res
!= NO_ERROR
) {
1882 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1884 dir
= dir
->getDirs().valueAt(i
);
1886 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1887 status_t res
= dir
->addDir(rootStr
, subdir
);
1888 if (res
!= NO_ERROR
) {
1896 mGroupEntries
.add(entry
);
1897 if (outGroup
) *outGroup
= group
;
1901 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1902 const sp
<AaptFile
>& file
, const String8
& resType
)
1904 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1905 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1906 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1907 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1910 subdir
->addFile(leafName
, grr
);
1914 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1919 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1920 const size_t dirCount
=resDirs
.size();
1921 sp
<AaptAssets
> current
= this;
1923 const int N
= bundle
->getFileSpecCount();
1926 * If a package manifest was specified, include that first.
1928 if (bundle
->getAndroidManifestFile() != NULL
) {
1929 // place at root of zip.
1930 String8
srcFile(bundle
->getAndroidManifestFile());
1931 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1937 * If a directory of custom assets was supplied, slurp 'em up.
1939 if (bundle
->getAssetSourceDir()) {
1940 const char* assetDir
= bundle
->getAssetSourceDir();
1942 FileType type
= getFileType(assetDir
);
1943 if (type
== kFileTypeNonexistent
) {
1944 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1945 return UNKNOWN_ERROR
;
1947 if (type
!= kFileTypeDirectory
) {
1948 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1949 return UNKNOWN_ERROR
;
1952 String8
assetRoot(assetDir
);
1953 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1954 AaptGroupEntry group
;
1955 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1956 String8(), mFullAssetPaths
);
1962 mGroupEntries
.add(group
);
1964 totalCount
+= count
;
1966 if (bundle
->getVerbose())
1967 printf("Found %d custom asset file%s in %s\n",
1968 count
, (count
==1) ? "" : "s", assetDir
);
1972 * If a directory of resource-specific assets was supplied, slurp 'em up.
1974 for (size_t i
=0; i
<dirCount
; i
++) {
1975 const char *res
= resDirs
[i
];
1977 type
= getFileType(res
);
1978 if (type
== kFileTypeNonexistent
) {
1979 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1980 return UNKNOWN_ERROR
;
1982 if (type
== kFileTypeDirectory
) {
1984 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1985 current
->setOverlay(nextOverlay
);
1986 current
= nextOverlay
;
1987 current
->setFullResPaths(mFullResPaths
);
1989 count
= current
->slurpResourceTree(bundle
, String8(res
));
1995 totalCount
+= count
;
1998 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1999 return UNKNOWN_ERROR
;
2005 * Now do any additional raw files.
2007 for (int arg
=0; arg
<N
; arg
++) {
2008 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
2010 FileType type
= getFileType(assetDir
);
2011 if (type
== kFileTypeNonexistent
) {
2012 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
2013 return UNKNOWN_ERROR
;
2015 if (type
!= kFileTypeDirectory
) {
2016 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2017 return UNKNOWN_ERROR
;
2020 String8
assetRoot(assetDir
);
2022 if (bundle
->getVerbose())
2023 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
2026 * Do a recursive traversal of subdir tree. We don't make any
2027 * guarantees about ordering, so we're okay with an inorder search
2028 * using whatever order the OS happens to hand back to us.
2030 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
2032 /* failure; report error and remove archive */
2036 totalCount
+= count
;
2038 if (bundle
->getVerbose())
2039 printf("Found %d asset file%s in %s\n",
2040 count
, (count
==1) ? "" : "s", assetDir
);
2044 if (count
!= NO_ERROR
) {
2049 count
= filter(bundle
);
2050 if (count
!= NO_ERROR
) {
2059 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
2060 const AaptGroupEntry
& kind
,
2061 const String8
& resType
,
2062 sp
<FilePathStore
>& fullResPaths
)
2064 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
2066 mGroupEntries
.add(kind
);
2072 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
2076 DIR* dir
= opendir(srcDir
.string());
2078 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
2079 return UNKNOWN_ERROR
;
2085 * Run through the directory, looking for dirs that match the
2089 struct dirent
* entry
= readdir(dir
);
2090 if (entry
== NULL
) {
2094 if (isHidden(srcDir
.string(), entry
->d_name
)) {
2098 String8
subdirName(srcDir
);
2099 subdirName
.appendPath(entry
->d_name
);
2101 AaptGroupEntry group
;
2103 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
2105 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2111 if (bundle
->getMaxResVersion() != NULL
&& group
.getVersionString().length() != 0) {
2112 int maxResInt
= atoi(bundle
->getMaxResVersion());
2113 const char *verString
= group
.getVersionString().string();
2114 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2115 if (dirVersionInt
> maxResInt
) {
2116 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2121 FileType type
= getFileType(subdirName
.string());
2123 if (type
== kFileTypeDirectory
) {
2124 sp
<AaptDir
> dir
= makeDir(resType
);
2125 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2126 resType
, mFullResPaths
);
2132 mGroupEntries
.add(group
);
2136 // Only add this directory if we don't already have a resource dir
2137 // for the current type. This ensures that we only add the dir once
2139 sp
<AaptDir
> rdir
= resDir(resType
);
2144 if (bundle
->getVerbose()) {
2145 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2161 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2164 SortedVector
<AaptGroupEntry
> entries
;
2166 ZipFile
* zip
= new ZipFile
;
2167 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2168 if (err
!= NO_ERROR
) {
2169 fprintf(stderr
, "error opening zip file %s\n", filename
);
2175 const int N
= zip
->getNumEntries();
2176 for (int i
=0; i
<N
; i
++) {
2177 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2178 if (entry
->getDeleted()) {
2182 String8
entryName(entry
->getFileName());
2184 String8 dirName
= entryName
.getPathDir();
2185 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2188 AaptGroupEntry kind
;
2191 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2192 // these are the resources, pull their type out of the directory name
2193 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2195 // these are untyped and don't have an AaptGroupEntry
2197 if (entries
.indexOf(kind
) < 0) {
2199 mGroupEntries
.add(kind
);
2202 // use the one from the zip file if they both exist.
2203 dir
->removeFile(entryName
.getPathLeaf());
2205 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2206 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2207 if (err
!= NO_ERROR
) {
2208 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2212 file
->setCompressionMethod(entry
->getCompressionMethod());
2215 if (entryName
== "AndroidManifest.xml") {
2216 printf("AndroidManifest.xml\n");
2218 printf("\n\nfile: %s\n", entryName
.string());
2221 size_t len
= entry
->getUncompressedLen();
2222 void* data
= zip
->uncompress(entry
);
2223 void* buf
= file
->editData(len
);
2224 memcpy(buf
, data
, len
);
2228 const unsigned char* p
= (unsigned char*)data
;
2229 const unsigned char* end
= p
+len
;
2231 for (int i
=0; i
<32 && p
< end
; i
++) {
2232 printf("0x%03x ", i
*0x10 + OFF
);
2233 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2234 printf(" %02x", *p
);
2251 status_t
AaptAssets::filter(Bundle
* bundle
)
2253 ResourceFilter reqFilter
;
2254 status_t err
= reqFilter
.parse(bundle
->getConfigurations());
2255 if (err
!= NO_ERROR
) {
2259 ResourceFilter prefFilter
;
2260 err
= prefFilter
.parse(bundle
->getPreferredConfigurations());
2261 if (err
!= NO_ERROR
) {
2265 if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) {
2269 if (bundle
->getVerbose()) {
2270 if (!reqFilter
.isEmpty()) {
2271 printf("Applying required filter: %s\n",
2272 bundle
->getConfigurations());
2274 if (!prefFilter
.isEmpty()) {
2275 printf("Applying preferred filter: %s\n",
2276 bundle
->getPreferredConfigurations());
2280 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2281 const size_t ND
= resdirs
.size();
2282 for (size_t i
=0; i
<ND
; i
++) {
2283 const sp
<AaptDir
>& dir
= resdirs
.itemAt(i
);
2284 if (dir
->getLeaf() == kValuesDir
) {
2285 // The "value" dir is special since a single file defines
2286 // multiple resources, so we can not do filtering on the
2287 // files themselves.
2290 if (dir
->getLeaf() == kMipmapDir
) {
2291 // We also skip the "mipmap" directory, since the point of this
2292 // is to include all densities without stripping. If you put
2293 // other configurations in here as well they won't be stripped
2294 // either... So don't do that. Seriously. What is wrong with you?
2298 const size_t NG
= dir
->getFiles().size();
2299 for (size_t j
=0; j
<NG
; j
++) {
2300 sp
<AaptGroup
> grp
= dir
->getFiles().valueAt(j
);
2302 // First remove any configurations we know we don't need.
2303 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2304 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2305 if (k
== 0 && grp
->getFiles().size() == 1) {
2306 // If this is the only file left, we need to keep it.
2307 // Otherwise the resource IDs we are using will be inconsistent
2308 // with what we get when not stripping. Sucky, but at least
2309 // for now we can rely on the back-end doing another filtering
2310 // pass to take this out and leave us with this resource name
2311 // containing no entries.
2314 if (file
->getPath().getPathExtension() == ".xml") {
2315 // We can't remove .xml files at this point, because when
2316 // we parse them they may add identifier resources, so
2317 // removing them can cause our resource identifiers to
2318 // become inconsistent.
2321 const ResTable_config
& config(file
->getGroupEntry().toParams());
2322 if (!reqFilter
.match(config
)) {
2323 if (bundle
->getVerbose()) {
2324 printf("Pruning unneeded resource: %s\n",
2325 file
->getPrintableSource().string());
2332 // Quick check: no preferred filters, nothing more to do.
2333 if (prefFilter
.isEmpty()) {
2337 // Now deal with preferred configurations.
2338 for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) {
2339 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2340 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2341 if (k
== 0 && grp
->getFiles().size() == 1) {
2342 // If this is the only file left, we need to keep it.
2343 // Otherwise the resource IDs we are using will be inconsistent
2344 // with what we get when not stripping. Sucky, but at least
2345 // for now we can rely on the back-end doing another filtering
2346 // pass to take this out and leave us with this resource name
2347 // containing no entries.
2350 if (file
->getPath().getPathExtension() == ".xml") {
2351 // We can't remove .xml files at this point, because when
2352 // we parse them they may add identifier resources, so
2353 // removing them can cause our resource identifiers to
2354 // become inconsistent.
2357 const ResTable_config
& config(file
->getGroupEntry().toParams());
2358 if (!prefFilter
.match(axis
, config
)) {
2359 // This is a resource we would prefer not to have. Check
2360 // to see if have a similar variation that we would like
2361 // to have and, if so, we can drop it.
2362 for (size_t m
=0; m
<grp
->getFiles().size(); m
++) {
2363 if (m
== k
) continue;
2364 sp
<AaptFile
> mfile
= grp
->getFiles().valueAt(m
);
2365 const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams());
2366 if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) {
2367 if (prefFilter
.match(axis
, mconfig
)) {
2368 if (bundle
->getVerbose()) {
2369 printf("Pruning unneeded resource: %s\n",
2370 file
->getPrintableSource().string());
2387 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2389 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2391 sym
= new AaptSymbols();
2392 mSymbols
.add(name
, sym
);
2397 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2399 if (!mHaveIncludedAssets
) {
2400 // Add in all includes.
2401 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2402 const size_t N
=incl
.size();
2403 for (size_t i
=0; i
<N
; i
++) {
2404 if (bundle
->getVerbose())
2405 printf("Including resources from package: %s\n", incl
[i
]);
2406 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2407 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2409 return UNKNOWN_ERROR
;
2412 mHaveIncludedAssets
= true;
2418 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2420 const ResTable
& res
= getIncludedResources();
2422 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2425 const ResTable
& AaptAssets::getIncludedResources() const
2427 return mIncludedAssets
.getResources(false);
2430 void AaptAssets::print(const String8
& prefix
) const
2432 String8
innerPrefix(prefix
);
2433 innerPrefix
.append(" ");
2434 String8
innerInnerPrefix(innerPrefix
);
2435 innerInnerPrefix
.append(" ");
2436 printf("%sConfigurations:\n", prefix
.string());
2437 const size_t N
=mGroupEntries
.size();
2438 for (size_t i
=0; i
<N
; i
++) {
2439 String8 cname
= mGroupEntries
.itemAt(i
).toDirName(String8());
2440 printf("%s %s\n", prefix
.string(),
2441 cname
!= "" ? cname
.string() : "(default)");
2444 printf("\n%sFiles:\n", prefix
.string());
2445 AaptDir::print(innerPrefix
);
2447 printf("\n%sResource Dirs:\n", prefix
.string());
2448 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2449 const size_t NR
= resdirs
.size();
2450 for (size_t i
=0; i
<NR
; i
++) {
2451 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2452 printf("%s Type %s\n", prefix
.string(), d
->getLeaf().string());
2453 d
->print(innerInnerPrefix
);
2457 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const
2459 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2460 const size_t N
= resdirs
.size();
2461 for (size_t i
=0; i
<N
; i
++) {
2462 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2463 if (d
->getLeaf() == name
) {
2471 valid_symbol_name(const String8
& symbol
)
2473 static char const * const KEYWORDS
[] = {
2474 "abstract", "assert", "boolean", "break",
2475 "byte", "case", "catch", "char", "class", "const", "continue",
2476 "default", "do", "double", "else", "enum", "extends", "final",
2477 "finally", "float", "for", "goto", "if", "implements", "import",
2478 "instanceof", "int", "interface", "long", "native", "new", "package",
2479 "private", "protected", "public", "return", "short", "static",
2480 "strictfp", "super", "switch", "synchronized", "this", "throw",
2481 "throws", "transient", "try", "void", "volatile", "while",
2482 "true", "false", "null",
2485 const char*const* k
= KEYWORDS
;
2486 const char*const s
= symbol
.string();
2488 if (0 == strcmp(s
, *k
)) {