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
;
1022 } else if (strcmp(name
, "appliance") == 0) {
1023 if (out
) out
->uiMode
=
1024 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
1025 | ResTable_config::UI_MODE_TYPE_APPLIANCE
;
1032 bool AaptGroupEntry::getUiModeNightName(const char* name
,
1033 ResTable_config
* out
)
1035 if (strcmp(name
, kWildcardName
) == 0) {
1036 if (out
) out
->uiMode
=
1037 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1038 | ResTable_config::UI_MODE_NIGHT_ANY
;
1040 } else if (strcmp(name
, "night") == 0) {
1041 if (out
) out
->uiMode
=
1042 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1043 | ResTable_config::UI_MODE_NIGHT_YES
;
1045 } else if (strcmp(name
, "notnight") == 0) {
1046 if (out
) out
->uiMode
=
1047 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
1048 | ResTable_config::UI_MODE_NIGHT_NO
;
1055 bool AaptGroupEntry::getDensityName(const char* name
,
1056 ResTable_config
* out
)
1058 if (strcmp(name
, kWildcardName
) == 0) {
1059 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
1063 if (strcmp(name
, "nodpi") == 0) {
1064 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
1068 if (strcmp(name
, "ldpi") == 0) {
1069 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
1073 if (strcmp(name
, "mdpi") == 0) {
1074 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
1078 if (strcmp(name
, "tvdpi") == 0) {
1079 if (out
) out
->density
= ResTable_config::DENSITY_TV
;
1083 if (strcmp(name
, "hdpi") == 0) {
1084 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
1088 if (strcmp(name
, "xhdpi") == 0) {
1089 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
*2;
1093 char* c
= (char*)name
;
1094 while (*c
>= '0' && *c
<= '9') {
1098 // check that we have 'dpi' after the last digit.
1099 if (toupper(c
[0]) != 'D' ||
1100 toupper(c
[1]) != 'P' ||
1101 toupper(c
[2]) != 'I' ||
1106 // temporarily replace the first letter with \0 to
1115 if (out
) out
->density
= d
;
1122 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1123 ResTable_config
* out
)
1125 if (strcmp(name
, kWildcardName
) == 0) {
1126 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1128 } else if (strcmp(name
, "notouch") == 0) {
1129 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1131 } else if (strcmp(name
, "stylus") == 0) {
1132 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1134 } else if (strcmp(name
, "finger") == 0) {
1135 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1142 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1143 ResTable_config
* out
)
1147 if (strcmp(name
, kWildcardName
) == 0) {
1148 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1149 value
= ResTable_config::KEYSHIDDEN_ANY
;
1150 } else if (strcmp(name
, "keysexposed") == 0) {
1151 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1152 value
= ResTable_config::KEYSHIDDEN_NO
;
1153 } else if (strcmp(name
, "keyshidden") == 0) {
1154 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1155 value
= ResTable_config::KEYSHIDDEN_YES
;
1156 } else if (strcmp(name
, "keyssoft") == 0) {
1157 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1158 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1162 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1169 bool AaptGroupEntry::getKeyboardName(const char* name
,
1170 ResTable_config
* out
)
1172 if (strcmp(name
, kWildcardName
) == 0) {
1173 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1175 } else if (strcmp(name
, "nokeys") == 0) {
1176 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1178 } else if (strcmp(name
, "qwerty") == 0) {
1179 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1181 } else if (strcmp(name
, "12key") == 0) {
1182 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1189 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1190 ResTable_config
* out
)
1194 if (strcmp(name
, kWildcardName
) == 0) {
1195 mask
= ResTable_config::MASK_NAVHIDDEN
;
1196 value
= ResTable_config::NAVHIDDEN_ANY
;
1197 } else if (strcmp(name
, "navexposed") == 0) {
1198 mask
= ResTable_config::MASK_NAVHIDDEN
;
1199 value
= ResTable_config::NAVHIDDEN_NO
;
1200 } else if (strcmp(name
, "navhidden") == 0) {
1201 mask
= ResTable_config::MASK_NAVHIDDEN
;
1202 value
= ResTable_config::NAVHIDDEN_YES
;
1206 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1213 bool AaptGroupEntry::getNavigationName(const char* name
,
1214 ResTable_config
* out
)
1216 if (strcmp(name
, kWildcardName
) == 0) {
1217 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1219 } else if (strcmp(name
, "nonav") == 0) {
1220 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1222 } else if (strcmp(name
, "dpad") == 0) {
1223 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1225 } else if (strcmp(name
, "trackball") == 0) {
1226 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1228 } else if (strcmp(name
, "wheel") == 0) {
1229 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1236 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1238 if (strcmp(name
, kWildcardName
) == 0) {
1240 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1241 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1246 const char* x
= name
;
1247 while (*x
>= '0' && *x
<= '9') x
++;
1248 if (x
== name
|| *x
!= 'x') return false;
1249 String8
xName(name
, x
-name
);
1253 while (*y
>= '0' && *y
<= '9') y
++;
1254 if (y
== name
|| *y
!= 0) return false;
1255 String8
yName(x
, y
-x
);
1257 uint16_t w
= (uint16_t)atoi(xName
.string());
1258 uint16_t h
= (uint16_t)atoi(yName
.string());
1264 out
->screenWidth
= w
;
1265 out
->screenHeight
= h
;
1271 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1273 if (strcmp(name
, kWildcardName
) == 0) {
1275 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1280 if (*name
!= 's') return false;
1282 if (*name
!= 'w') return false;
1284 const char* x
= name
;
1285 while (*x
>= '0' && *x
<= '9') x
++;
1286 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1287 String8
xName(name
, x
-name
);
1290 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1296 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1298 if (strcmp(name
, kWildcardName
) == 0) {
1300 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1305 if (*name
!= 'w') return false;
1307 const char* x
= name
;
1308 while (*x
>= '0' && *x
<= '9') x
++;
1309 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1310 String8
xName(name
, x
-name
);
1313 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1319 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1321 if (strcmp(name
, kWildcardName
) == 0) {
1323 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1328 if (*name
!= 'h') return false;
1330 const char* x
= name
;
1331 while (*x
>= '0' && *x
<= '9') x
++;
1332 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1333 String8
xName(name
, x
-name
);
1336 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1342 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1344 if (strcmp(name
, kWildcardName
) == 0) {
1346 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1347 out
->minorVersion
= out
->MINORVERSION_ANY
;
1357 const char* s
= name
;
1358 while (*s
>= '0' && *s
<= '9') s
++;
1359 if (s
== name
|| *s
!= 0) return false;
1360 String8
sdkName(name
, s
-name
);
1363 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1364 out
->minorVersion
= 0;
1370 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1372 int v
= mcc
.compare(o
.mcc
);
1373 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1374 if (v
== 0) v
= locale
.compare(o
.locale
);
1375 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1376 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1377 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1378 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1379 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1380 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1381 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1382 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1383 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1384 if (v
== 0) v
= density
.compare(o
.density
);
1385 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1386 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1387 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1388 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1389 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1390 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1391 if (v
== 0) v
= version
.compare(o
.version
);
1395 const ResTable_config
& AaptGroupEntry::toParams() const
1397 if (!mParamsChanged
) {
1401 mParamsChanged
= false;
1402 ResTable_config
& params(mParams
);
1403 memset(¶ms
, 0, sizeof(params
));
1404 getMccName(mcc
.string(), ¶ms
);
1405 getMncName(mnc
.string(), ¶ms
);
1406 getLocaleName(locale
.string(), ¶ms
);
1407 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1408 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1409 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1410 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1411 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1412 getOrientationName(orientation
.string(), ¶ms
);
1413 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1414 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1415 getDensityName(density
.string(), ¶ms
);
1416 getTouchscreenName(touchscreen
.string(), ¶ms
);
1417 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1418 getKeyboardName(keyboard
.string(), ¶ms
);
1419 getNavHiddenName(navHidden
.string(), ¶ms
);
1420 getNavigationName(navigation
.string(), ¶ms
);
1421 getScreenSizeName(screenSize
.string(), ¶ms
);
1422 getVersionName(version
.string(), ¶ms
);
1424 // Fix up version number based on specified parameters.
1426 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1427 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1428 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1429 minSdk
= SDK_HONEYCOMB_MR2
;
1430 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1431 != ResTable_config::UI_MODE_TYPE_ANY
1432 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1433 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1435 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1436 != ResTable_config::SCREENSIZE_ANY
1437 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1438 != ResTable_config::SCREENLONG_ANY
1439 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1443 if (minSdk
> params
.sdkVersion
) {
1444 params
.sdkVersion
= minSdk
;
1450 // =========================================================================
1451 // =========================================================================
1452 // =========================================================================
1454 void* AaptFile::editData(size_t size
)
1456 if (size
<= mBufferSize
) {
1460 size_t allocSize
= (size
*3)/2;
1461 void* buf
= realloc(mData
, allocSize
);
1467 mBufferSize
= allocSize
;
1471 void* AaptFile::editData(size_t* outSize
)
1474 *outSize
= mDataSize
;
1479 void* AaptFile::padData(size_t wordSize
)
1481 const size_t extra
= mDataSize%wordSize
;
1486 size_t initial
= mDataSize
;
1487 void* data
= editData(initial
+(wordSize
-extra
));
1489 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1494 status_t
AaptFile::writeData(const void* data
, size_t size
)
1496 size_t end
= mDataSize
;
1497 size_t total
= size
+ end
;
1498 void* buf
= editData(total
);
1500 return UNKNOWN_ERROR
;
1502 memcpy(((char*)buf
)+end
, data
, size
);
1506 void AaptFile::clearData()
1508 if (mData
!= NULL
) free(mData
);
1514 String8
AaptFile::getPrintableSource() const
1517 String8
name(mGroupEntry
.toDirName(String8()));
1518 name
.appendPath(mPath
);
1519 name
.append(" #generated");
1525 // =========================================================================
1526 // =========================================================================
1527 // =========================================================================
1529 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1531 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1532 file
->mPath
= mPath
;
1533 mFiles
.add(file
->getGroupEntry(), file
);
1538 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1539 file
->getSourceFile().string(),
1540 file
->getGroupEntry().toDirName(String8()).string(),
1541 mLeaf
.string(), mPath
.string());
1544 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1545 getPrintableSource().string());
1546 return UNKNOWN_ERROR
;
1549 void AaptGroup::removeFile(size_t index
)
1551 mFiles
.removeItemsAt(index
);
1554 void AaptGroup::print(const String8
& prefix
) const
1556 printf("%s%s\n", prefix
.string(), getPath().string());
1557 const size_t N
=mFiles
.size();
1559 for (i
=0; i
<N
; i
++) {
1560 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1561 const AaptGroupEntry
& e
= file
->getGroupEntry();
1562 if (file
->hasData()) {
1563 printf("%s Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(),
1564 (int)file
->getSize());
1566 printf("%s Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(),
1567 file
->getPrintableSource().string());
1569 //printf("%s File Group Entry: %s\n", prefix.string(),
1570 // file->getGroupEntry().toDirName(String8()).string());
1574 String8
AaptGroup::getPrintableSource() const
1576 if (mFiles
.size() > 0) {
1577 // Arbitrarily pull the first source file out of the list.
1578 return mFiles
.valueAt(0)->getPrintableSource();
1581 // Should never hit this case, but to be safe...
1586 // =========================================================================
1587 // =========================================================================
1588 // =========================================================================
1590 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1592 if (mFiles
.indexOfKey(name
) >= 0) {
1593 return ALREADY_EXISTS
;
1595 mFiles
.add(name
, file
);
1599 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1601 if (mDirs
.indexOfKey(name
) >= 0) {
1602 return ALREADY_EXISTS
;
1604 mDirs
.add(name
, dir
);
1608 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1611 String8 remain
= path
;
1613 sp
<AaptDir
> subdir
= this;
1614 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1615 subdir
= subdir
->makeDir(name
);
1618 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1620 return subdir
->mDirs
.valueAt(i
);
1622 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1623 subdir
->mDirs
.add(name
, dir
);
1627 void AaptDir::removeFile(const String8
& name
)
1629 mFiles
.removeItem(name
);
1632 void AaptDir::removeDir(const String8
& name
)
1634 mDirs
.removeItem(name
);
1637 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1639 sp
<AaptGroup
> group
;
1640 if (mFiles
.indexOfKey(leafName
) >= 0) {
1641 group
= mFiles
.valueFor(leafName
);
1643 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1644 mFiles
.add(leafName
, group
);
1647 return group
->addFile(file
);
1650 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1651 const AaptGroupEntry
& kind
, const String8
& resType
,
1652 sp
<FilePathStore
>& fullResPaths
)
1654 Vector
<String8
> fileNames
;
1658 dir
= opendir(srcDir
.string());
1660 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1661 return UNKNOWN_ERROR
;
1665 * Slurp the filenames out of the directory.
1668 struct dirent
* entry
;
1670 entry
= readdir(dir
);
1674 if (isHidden(srcDir
.string(), entry
->d_name
))
1677 String8
name(entry
->d_name
);
1678 fileNames
.add(name
);
1679 // Add fully qualified path for dependency purposes
1680 // if we're collecting them
1681 if (fullResPaths
!= NULL
) {
1682 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1691 * Stash away the files and recursively descend into subdirectories.
1693 const size_t N
= fileNames
.size();
1695 for (i
= 0; i
< N
; i
++) {
1696 String8
pathName(srcDir
);
1699 pathName
.appendPath(fileNames
[i
].string());
1700 type
= getFileType(pathName
.string());
1701 if (type
== kFileTypeDirectory
) {
1703 bool notAdded
= false;
1704 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1705 subdir
= mDirs
.valueFor(fileNames
[i
]);
1707 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1710 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1711 resType
, fullResPaths
);
1712 if (res
< NO_ERROR
) {
1715 if (res
> 0 && notAdded
) {
1716 mDirs
.add(fileNames
[i
], subdir
);
1719 } else if (type
== kFileTypeRegular
) {
1720 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1721 status_t err
= addLeafFile(fileNames
[i
], file
);
1722 if (err
!= NO_ERROR
) {
1729 if (bundle
->getVerbose())
1730 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1737 status_t
AaptDir::validate() const
1739 const size_t NF
= mFiles
.size();
1740 const size_t ND
= mDirs
.size();
1742 for (i
= 0; i
< NF
; i
++) {
1743 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1744 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1745 "Invalid filename. Unable to add.");
1746 return UNKNOWN_ERROR
;
1750 for (j
= i
+1; j
< NF
; j
++) {
1751 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1752 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1753 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1754 "File is case-insensitive equivalent to: %s",
1755 mFiles
.valueAt(j
)->getPrintableSource().string());
1756 return UNKNOWN_ERROR
;
1759 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1760 // (this is mostly caught by the "marked" stuff, below)
1763 for (j
= 0; j
< ND
; j
++) {
1764 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1765 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1766 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1767 "File conflicts with dir from: %s",
1768 mDirs
.valueAt(j
)->getPrintableSource().string());
1769 return UNKNOWN_ERROR
;
1774 for (i
= 0; i
< ND
; i
++) {
1775 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1776 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1777 "Invalid directory name, unable to add.");
1778 return UNKNOWN_ERROR
;
1782 for (j
= i
+1; j
< ND
; j
++) {
1783 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1784 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1785 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1786 "Directory is case-insensitive equivalent to: %s",
1787 mDirs
.valueAt(j
)->getPrintableSource().string());
1788 return UNKNOWN_ERROR
;
1792 status_t err
= mDirs
.valueAt(i
)->validate();
1793 if (err
!= NO_ERROR
) {
1801 void AaptDir::print(const String8
& prefix
) const
1803 const size_t ND
=getDirs().size();
1805 for (i
=0; i
<ND
; i
++) {
1806 getDirs().valueAt(i
)->print(prefix
);
1809 const size_t NF
=getFiles().size();
1810 for (i
=0; i
<NF
; i
++) {
1811 getFiles().valueAt(i
)->print(prefix
);
1815 String8
AaptDir::getPrintableSource() const
1817 if (mFiles
.size() > 0) {
1818 // Arbitrarily pull the first file out of the list as the source dir.
1819 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1821 if (mDirs
.size() > 0) {
1822 // Or arbitrarily pull the first dir out of the list as the source dir.
1823 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1826 // Should never hit this case, but to be safe...
1831 // =========================================================================
1832 // =========================================================================
1833 // =========================================================================
1835 AaptAssets::AaptAssets()
1836 : AaptDir(String8(), String8()),
1837 mChanged(false), mHaveIncludedAssets(false), mRes(NULL
)
1841 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const {
1844 return mGroupEntries
;
1847 status_t
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1850 return AaptDir::addFile(name
, file
);
1853 sp
<AaptFile
> AaptAssets::addFile(
1854 const String8
& filePath
, const AaptGroupEntry
& entry
,
1855 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1856 const String8
& resType
)
1858 sp
<AaptDir
> dir
= this;
1859 sp
<AaptGroup
> group
;
1861 String8 root
, remain(filePath
), partialPath
;
1862 while (remain
.length() > 0) {
1863 root
= remain
.walkPath(&remain
);
1864 partialPath
.appendPath(root
);
1866 const String8
rootStr(root
);
1868 if (remain
.length() == 0) {
1869 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1871 group
= dir
->getFiles().valueAt(i
);
1873 group
= new AaptGroup(rootStr
, filePath
);
1874 status_t res
= dir
->addFile(rootStr
, group
);
1875 if (res
!= NO_ERROR
) {
1879 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1880 status_t res
= group
->addFile(file
);
1881 if (res
!= NO_ERROR
) {
1887 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1889 dir
= dir
->getDirs().valueAt(i
);
1891 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1892 status_t res
= dir
->addDir(rootStr
, subdir
);
1893 if (res
!= NO_ERROR
) {
1901 mGroupEntries
.add(entry
);
1902 if (outGroup
) *outGroup
= group
;
1906 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1907 const sp
<AaptFile
>& file
, const String8
& resType
)
1909 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1910 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1911 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1912 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1915 subdir
->addFile(leafName
, grr
);
1919 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1924 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1925 const size_t dirCount
=resDirs
.size();
1926 sp
<AaptAssets
> current
= this;
1928 const int N
= bundle
->getFileSpecCount();
1931 * If a package manifest was specified, include that first.
1933 if (bundle
->getAndroidManifestFile() != NULL
) {
1934 // place at root of zip.
1935 String8
srcFile(bundle
->getAndroidManifestFile());
1936 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1942 * If a directory of custom assets was supplied, slurp 'em up.
1944 if (bundle
->getAssetSourceDir()) {
1945 const char* assetDir
= bundle
->getAssetSourceDir();
1947 FileType type
= getFileType(assetDir
);
1948 if (type
== kFileTypeNonexistent
) {
1949 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1950 return UNKNOWN_ERROR
;
1952 if (type
!= kFileTypeDirectory
) {
1953 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1954 return UNKNOWN_ERROR
;
1957 String8
assetRoot(assetDir
);
1958 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1959 AaptGroupEntry group
;
1960 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1961 String8(), mFullAssetPaths
);
1967 mGroupEntries
.add(group
);
1969 totalCount
+= count
;
1971 if (bundle
->getVerbose())
1972 printf("Found %d custom asset file%s in %s\n",
1973 count
, (count
==1) ? "" : "s", assetDir
);
1977 * If a directory of resource-specific assets was supplied, slurp 'em up.
1979 for (size_t i
=0; i
<dirCount
; i
++) {
1980 const char *res
= resDirs
[i
];
1982 type
= getFileType(res
);
1983 if (type
== kFileTypeNonexistent
) {
1984 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1985 return UNKNOWN_ERROR
;
1987 if (type
== kFileTypeDirectory
) {
1989 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1990 current
->setOverlay(nextOverlay
);
1991 current
= nextOverlay
;
1992 current
->setFullResPaths(mFullResPaths
);
1994 count
= current
->slurpResourceTree(bundle
, String8(res
));
2000 totalCount
+= count
;
2003 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
2004 return UNKNOWN_ERROR
;
2010 * Now do any additional raw files.
2012 for (int arg
=0; arg
<N
; arg
++) {
2013 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
2015 FileType type
= getFileType(assetDir
);
2016 if (type
== kFileTypeNonexistent
) {
2017 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
2018 return UNKNOWN_ERROR
;
2020 if (type
!= kFileTypeDirectory
) {
2021 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2022 return UNKNOWN_ERROR
;
2025 String8
assetRoot(assetDir
);
2027 if (bundle
->getVerbose())
2028 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
2031 * Do a recursive traversal of subdir tree. We don't make any
2032 * guarantees about ordering, so we're okay with an inorder search
2033 * using whatever order the OS happens to hand back to us.
2035 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
2037 /* failure; report error and remove archive */
2041 totalCount
+= count
;
2043 if (bundle
->getVerbose())
2044 printf("Found %d asset file%s in %s\n",
2045 count
, (count
==1) ? "" : "s", assetDir
);
2049 if (count
!= NO_ERROR
) {
2054 count
= filter(bundle
);
2055 if (count
!= NO_ERROR
) {
2064 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
2065 const AaptGroupEntry
& kind
,
2066 const String8
& resType
,
2067 sp
<FilePathStore
>& fullResPaths
)
2069 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
2071 mGroupEntries
.add(kind
);
2077 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
2081 DIR* dir
= opendir(srcDir
.string());
2083 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
2084 return UNKNOWN_ERROR
;
2090 * Run through the directory, looking for dirs that match the
2094 struct dirent
* entry
= readdir(dir
);
2095 if (entry
== NULL
) {
2099 if (isHidden(srcDir
.string(), entry
->d_name
)) {
2103 String8
subdirName(srcDir
);
2104 subdirName
.appendPath(entry
->d_name
);
2106 AaptGroupEntry group
;
2108 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
2110 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2116 if (bundle
->getMaxResVersion() != NULL
&& group
.getVersionString().length() != 0) {
2117 int maxResInt
= atoi(bundle
->getMaxResVersion());
2118 const char *verString
= group
.getVersionString().string();
2119 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2120 if (dirVersionInt
> maxResInt
) {
2121 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2126 FileType type
= getFileType(subdirName
.string());
2128 if (type
== kFileTypeDirectory
) {
2129 sp
<AaptDir
> dir
= makeDir(resType
);
2130 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2131 resType
, mFullResPaths
);
2137 mGroupEntries
.add(group
);
2141 // Only add this directory if we don't already have a resource dir
2142 // for the current type. This ensures that we only add the dir once
2144 sp
<AaptDir
> rdir
= resDir(resType
);
2149 if (bundle
->getVerbose()) {
2150 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2166 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2169 SortedVector
<AaptGroupEntry
> entries
;
2171 ZipFile
* zip
= new ZipFile
;
2172 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2173 if (err
!= NO_ERROR
) {
2174 fprintf(stderr
, "error opening zip file %s\n", filename
);
2180 const int N
= zip
->getNumEntries();
2181 for (int i
=0; i
<N
; i
++) {
2182 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2183 if (entry
->getDeleted()) {
2187 String8
entryName(entry
->getFileName());
2189 String8 dirName
= entryName
.getPathDir();
2190 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2193 AaptGroupEntry kind
;
2196 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2197 // these are the resources, pull their type out of the directory name
2198 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2200 // these are untyped and don't have an AaptGroupEntry
2202 if (entries
.indexOf(kind
) < 0) {
2204 mGroupEntries
.add(kind
);
2207 // use the one from the zip file if they both exist.
2208 dir
->removeFile(entryName
.getPathLeaf());
2210 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2211 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2212 if (err
!= NO_ERROR
) {
2213 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2217 file
->setCompressionMethod(entry
->getCompressionMethod());
2220 if (entryName
== "AndroidManifest.xml") {
2221 printf("AndroidManifest.xml\n");
2223 printf("\n\nfile: %s\n", entryName
.string());
2226 size_t len
= entry
->getUncompressedLen();
2227 void* data
= zip
->uncompress(entry
);
2228 void* buf
= file
->editData(len
);
2229 memcpy(buf
, data
, len
);
2233 const unsigned char* p
= (unsigned char*)data
;
2234 const unsigned char* end
= p
+len
;
2236 for (int i
=0; i
<32 && p
< end
; i
++) {
2237 printf("0x%03x ", i
*0x10 + OFF
);
2238 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2239 printf(" %02x", *p
);
2256 status_t
AaptAssets::filter(Bundle
* bundle
)
2258 ResourceFilter reqFilter
;
2259 status_t err
= reqFilter
.parse(bundle
->getConfigurations());
2260 if (err
!= NO_ERROR
) {
2264 ResourceFilter prefFilter
;
2265 err
= prefFilter
.parse(bundle
->getPreferredConfigurations());
2266 if (err
!= NO_ERROR
) {
2270 if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) {
2274 if (bundle
->getVerbose()) {
2275 if (!reqFilter
.isEmpty()) {
2276 printf("Applying required filter: %s\n",
2277 bundle
->getConfigurations());
2279 if (!prefFilter
.isEmpty()) {
2280 printf("Applying preferred filter: %s\n",
2281 bundle
->getPreferredConfigurations());
2285 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2286 const size_t ND
= resdirs
.size();
2287 for (size_t i
=0; i
<ND
; i
++) {
2288 const sp
<AaptDir
>& dir
= resdirs
.itemAt(i
);
2289 if (dir
->getLeaf() == kValuesDir
) {
2290 // The "value" dir is special since a single file defines
2291 // multiple resources, so we can not do filtering on the
2292 // files themselves.
2295 if (dir
->getLeaf() == kMipmapDir
) {
2296 // We also skip the "mipmap" directory, since the point of this
2297 // is to include all densities without stripping. If you put
2298 // other configurations in here as well they won't be stripped
2299 // either... So don't do that. Seriously. What is wrong with you?
2303 const size_t NG
= dir
->getFiles().size();
2304 for (size_t j
=0; j
<NG
; j
++) {
2305 sp
<AaptGroup
> grp
= dir
->getFiles().valueAt(j
);
2307 // First remove any configurations we know we don't need.
2308 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2309 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2310 if (k
== 0 && grp
->getFiles().size() == 1) {
2311 // If this is the only file left, we need to keep it.
2312 // Otherwise the resource IDs we are using will be inconsistent
2313 // with what we get when not stripping. Sucky, but at least
2314 // for now we can rely on the back-end doing another filtering
2315 // pass to take this out and leave us with this resource name
2316 // containing no entries.
2319 if (file
->getPath().getPathExtension() == ".xml") {
2320 // We can't remove .xml files at this point, because when
2321 // we parse them they may add identifier resources, so
2322 // removing them can cause our resource identifiers to
2323 // become inconsistent.
2326 const ResTable_config
& config(file
->getGroupEntry().toParams());
2327 if (!reqFilter
.match(config
)) {
2328 if (bundle
->getVerbose()) {
2329 printf("Pruning unneeded resource: %s\n",
2330 file
->getPrintableSource().string());
2337 // Quick check: no preferred filters, nothing more to do.
2338 if (prefFilter
.isEmpty()) {
2342 // Now deal with preferred configurations.
2343 for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) {
2344 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2345 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2346 if (k
== 0 && grp
->getFiles().size() == 1) {
2347 // If this is the only file left, we need to keep it.
2348 // Otherwise the resource IDs we are using will be inconsistent
2349 // with what we get when not stripping. Sucky, but at least
2350 // for now we can rely on the back-end doing another filtering
2351 // pass to take this out and leave us with this resource name
2352 // containing no entries.
2355 if (file
->getPath().getPathExtension() == ".xml") {
2356 // We can't remove .xml files at this point, because when
2357 // we parse them they may add identifier resources, so
2358 // removing them can cause our resource identifiers to
2359 // become inconsistent.
2362 const ResTable_config
& config(file
->getGroupEntry().toParams());
2363 if (!prefFilter
.match(axis
, config
)) {
2364 // This is a resource we would prefer not to have. Check
2365 // to see if have a similar variation that we would like
2366 // to have and, if so, we can drop it.
2367 for (size_t m
=0; m
<grp
->getFiles().size(); m
++) {
2368 if (m
== k
) continue;
2369 sp
<AaptFile
> mfile
= grp
->getFiles().valueAt(m
);
2370 const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams());
2371 if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) {
2372 if (prefFilter
.match(axis
, mconfig
)) {
2373 if (bundle
->getVerbose()) {
2374 printf("Pruning unneeded resource: %s\n",
2375 file
->getPrintableSource().string());
2392 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2394 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2396 sym
= new AaptSymbols();
2397 mSymbols
.add(name
, sym
);
2402 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2404 if (!mHaveIncludedAssets
) {
2405 // Add in all includes.
2406 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2407 const size_t N
=incl
.size();
2408 for (size_t i
=0; i
<N
; i
++) {
2409 if (bundle
->getVerbose())
2410 printf("Including resources from package: %s\n", incl
[i
]);
2411 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2412 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2414 return UNKNOWN_ERROR
;
2417 mHaveIncludedAssets
= true;
2423 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2425 const ResTable
& res
= getIncludedResources();
2427 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2430 const ResTable
& AaptAssets::getIncludedResources() const
2432 return mIncludedAssets
.getResources(false);
2435 void AaptAssets::print(const String8
& prefix
) const
2437 String8
innerPrefix(prefix
);
2438 innerPrefix
.append(" ");
2439 String8
innerInnerPrefix(innerPrefix
);
2440 innerInnerPrefix
.append(" ");
2441 printf("%sConfigurations:\n", prefix
.string());
2442 const size_t N
=mGroupEntries
.size();
2443 for (size_t i
=0; i
<N
; i
++) {
2444 String8 cname
= mGroupEntries
.itemAt(i
).toDirName(String8());
2445 printf("%s %s\n", prefix
.string(),
2446 cname
!= "" ? cname
.string() : "(default)");
2449 printf("\n%sFiles:\n", prefix
.string());
2450 AaptDir::print(innerPrefix
);
2452 printf("\n%sResource Dirs:\n", prefix
.string());
2453 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2454 const size_t NR
= resdirs
.size();
2455 for (size_t i
=0; i
<NR
; i
++) {
2456 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2457 printf("%s Type %s\n", prefix
.string(), d
->getLeaf().string());
2458 d
->print(innerInnerPrefix
);
2462 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const
2464 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2465 const size_t N
= resdirs
.size();
2466 for (size_t i
=0; i
<N
; i
++) {
2467 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2468 if (d
->getLeaf() == name
) {
2476 valid_symbol_name(const String8
& symbol
)
2478 static char const * const KEYWORDS
[] = {
2479 "abstract", "assert", "boolean", "break",
2480 "byte", "case", "catch", "char", "class", "const", "continue",
2481 "default", "do", "double", "else", "enum", "extends", "final",
2482 "finally", "float", "for", "goto", "if", "implements", "import",
2483 "instanceof", "int", "interface", "long", "native", "new", "package",
2484 "private", "protected", "public", "return", "short", "static",
2485 "strictfp", "super", "switch", "synchronized", "this", "throw",
2486 "throws", "transient", "try", "void", "volatile", "while",
2487 "true", "false", "null",
2490 const char*const* k
= KEYWORDS
;
2491 const char*const s
= symbol
.string();
2493 if (0 == strcmp(s
, *k
)) {