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_XHIGH
;
1093 if (strcmp(name
, "xxhdpi") == 0) {
1094 if (out
) out
->density
= ResTable_config::DENSITY_XXHIGH
;
1098 char* c
= (char*)name
;
1099 while (*c
>= '0' && *c
<= '9') {
1103 // check that we have 'dpi' after the last digit.
1104 if (toupper(c
[0]) != 'D' ||
1105 toupper(c
[1]) != 'P' ||
1106 toupper(c
[2]) != 'I' ||
1111 // temporarily replace the first letter with \0 to
1120 if (out
) out
->density
= d
;
1127 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1128 ResTable_config
* out
)
1130 if (strcmp(name
, kWildcardName
) == 0) {
1131 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1133 } else if (strcmp(name
, "notouch") == 0) {
1134 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1136 } else if (strcmp(name
, "stylus") == 0) {
1137 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1139 } else if (strcmp(name
, "finger") == 0) {
1140 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1147 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1148 ResTable_config
* out
)
1152 if (strcmp(name
, kWildcardName
) == 0) {
1153 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1154 value
= ResTable_config::KEYSHIDDEN_ANY
;
1155 } else if (strcmp(name
, "keysexposed") == 0) {
1156 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1157 value
= ResTable_config::KEYSHIDDEN_NO
;
1158 } else if (strcmp(name
, "keyshidden") == 0) {
1159 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1160 value
= ResTable_config::KEYSHIDDEN_YES
;
1161 } else if (strcmp(name
, "keyssoft") == 0) {
1162 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1163 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1167 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1174 bool AaptGroupEntry::getKeyboardName(const char* name
,
1175 ResTable_config
* out
)
1177 if (strcmp(name
, kWildcardName
) == 0) {
1178 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1180 } else if (strcmp(name
, "nokeys") == 0) {
1181 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1183 } else if (strcmp(name
, "qwerty") == 0) {
1184 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1186 } else if (strcmp(name
, "12key") == 0) {
1187 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1194 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1195 ResTable_config
* out
)
1199 if (strcmp(name
, kWildcardName
) == 0) {
1200 mask
= ResTable_config::MASK_NAVHIDDEN
;
1201 value
= ResTable_config::NAVHIDDEN_ANY
;
1202 } else if (strcmp(name
, "navexposed") == 0) {
1203 mask
= ResTable_config::MASK_NAVHIDDEN
;
1204 value
= ResTable_config::NAVHIDDEN_NO
;
1205 } else if (strcmp(name
, "navhidden") == 0) {
1206 mask
= ResTable_config::MASK_NAVHIDDEN
;
1207 value
= ResTable_config::NAVHIDDEN_YES
;
1211 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1218 bool AaptGroupEntry::getNavigationName(const char* name
,
1219 ResTable_config
* out
)
1221 if (strcmp(name
, kWildcardName
) == 0) {
1222 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1224 } else if (strcmp(name
, "nonav") == 0) {
1225 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1227 } else if (strcmp(name
, "dpad") == 0) {
1228 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1230 } else if (strcmp(name
, "trackball") == 0) {
1231 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1233 } else if (strcmp(name
, "wheel") == 0) {
1234 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1241 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1243 if (strcmp(name
, kWildcardName
) == 0) {
1245 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1246 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1251 const char* x
= name
;
1252 while (*x
>= '0' && *x
<= '9') x
++;
1253 if (x
== name
|| *x
!= 'x') return false;
1254 String8
xName(name
, x
-name
);
1258 while (*y
>= '0' && *y
<= '9') y
++;
1259 if (y
== name
|| *y
!= 0) return false;
1260 String8
yName(x
, y
-x
);
1262 uint16_t w
= (uint16_t)atoi(xName
.string());
1263 uint16_t h
= (uint16_t)atoi(yName
.string());
1269 out
->screenWidth
= w
;
1270 out
->screenHeight
= h
;
1276 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1278 if (strcmp(name
, kWildcardName
) == 0) {
1280 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1285 if (*name
!= 's') return false;
1287 if (*name
!= 'w') return false;
1289 const char* x
= name
;
1290 while (*x
>= '0' && *x
<= '9') x
++;
1291 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1292 String8
xName(name
, x
-name
);
1295 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1301 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1303 if (strcmp(name
, kWildcardName
) == 0) {
1305 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1310 if (*name
!= 'w') return false;
1312 const char* x
= name
;
1313 while (*x
>= '0' && *x
<= '9') x
++;
1314 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1315 String8
xName(name
, x
-name
);
1318 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1324 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1326 if (strcmp(name
, kWildcardName
) == 0) {
1328 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1333 if (*name
!= 'h') return false;
1335 const char* x
= name
;
1336 while (*x
>= '0' && *x
<= '9') x
++;
1337 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1338 String8
xName(name
, x
-name
);
1341 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1347 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1349 if (strcmp(name
, kWildcardName
) == 0) {
1351 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1352 out
->minorVersion
= out
->MINORVERSION_ANY
;
1362 const char* s
= name
;
1363 while (*s
>= '0' && *s
<= '9') s
++;
1364 if (s
== name
|| *s
!= 0) return false;
1365 String8
sdkName(name
, s
-name
);
1368 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1369 out
->minorVersion
= 0;
1375 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1377 int v
= mcc
.compare(o
.mcc
);
1378 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1379 if (v
== 0) v
= locale
.compare(o
.locale
);
1380 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1381 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1382 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1383 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1384 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1385 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1386 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1387 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1388 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1389 if (v
== 0) v
= density
.compare(o
.density
);
1390 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1391 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1392 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1393 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1394 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1395 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1396 if (v
== 0) v
= version
.compare(o
.version
);
1400 const ResTable_config
& AaptGroupEntry::toParams() const
1402 if (!mParamsChanged
) {
1406 mParamsChanged
= false;
1407 ResTable_config
& params(mParams
);
1408 memset(¶ms
, 0, sizeof(params
));
1409 getMccName(mcc
.string(), ¶ms
);
1410 getMncName(mnc
.string(), ¶ms
);
1411 getLocaleName(locale
.string(), ¶ms
);
1412 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1413 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1414 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1415 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1416 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1417 getOrientationName(orientation
.string(), ¶ms
);
1418 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1419 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1420 getDensityName(density
.string(), ¶ms
);
1421 getTouchscreenName(touchscreen
.string(), ¶ms
);
1422 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1423 getKeyboardName(keyboard
.string(), ¶ms
);
1424 getNavHiddenName(navHidden
.string(), ¶ms
);
1425 getNavigationName(navigation
.string(), ¶ms
);
1426 getScreenSizeName(screenSize
.string(), ¶ms
);
1427 getVersionName(version
.string(), ¶ms
);
1429 // Fix up version number based on specified parameters.
1431 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1432 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1433 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1434 minSdk
= SDK_HONEYCOMB_MR2
;
1435 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1436 != ResTable_config::UI_MODE_TYPE_ANY
1437 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1438 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1440 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1441 != ResTable_config::SCREENSIZE_ANY
1442 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1443 != ResTable_config::SCREENLONG_ANY
1444 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1448 if (minSdk
> params
.sdkVersion
) {
1449 params
.sdkVersion
= minSdk
;
1455 // =========================================================================
1456 // =========================================================================
1457 // =========================================================================
1459 void* AaptFile::editData(size_t size
)
1461 if (size
<= mBufferSize
) {
1465 size_t allocSize
= (size
*3)/2;
1466 void* buf
= realloc(mData
, allocSize
);
1472 mBufferSize
= allocSize
;
1476 void* AaptFile::editData(size_t* outSize
)
1479 *outSize
= mDataSize
;
1484 void* AaptFile::padData(size_t wordSize
)
1486 const size_t extra
= mDataSize%wordSize
;
1491 size_t initial
= mDataSize
;
1492 void* data
= editData(initial
+(wordSize
-extra
));
1494 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1499 status_t
AaptFile::writeData(const void* data
, size_t size
)
1501 size_t end
= mDataSize
;
1502 size_t total
= size
+ end
;
1503 void* buf
= editData(total
);
1505 return UNKNOWN_ERROR
;
1507 memcpy(((char*)buf
)+end
, data
, size
);
1511 void AaptFile::clearData()
1513 if (mData
!= NULL
) free(mData
);
1519 String8
AaptFile::getPrintableSource() const
1522 String8
name(mGroupEntry
.toDirName(String8()));
1523 name
.appendPath(mPath
);
1524 name
.append(" #generated");
1530 // =========================================================================
1531 // =========================================================================
1532 // =========================================================================
1534 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1536 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1537 file
->mPath
= mPath
;
1538 mFiles
.add(file
->getGroupEntry(), file
);
1543 printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
1544 file
->getSourceFile().string(),
1545 file
->getGroupEntry().toDirName(String8()).string(),
1546 mLeaf
.string(), mPath
.string());
1549 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1550 getPrintableSource().string());
1551 return UNKNOWN_ERROR
;
1554 void AaptGroup::removeFile(size_t index
)
1556 mFiles
.removeItemsAt(index
);
1559 void AaptGroup::print(const String8
& prefix
) const
1561 printf("%s%s\n", prefix
.string(), getPath().string());
1562 const size_t N
=mFiles
.size();
1564 for (i
=0; i
<N
; i
++) {
1565 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1566 const AaptGroupEntry
& e
= file
->getGroupEntry();
1567 if (file
->hasData()) {
1568 printf("%s Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(),
1569 (int)file
->getSize());
1571 printf("%s Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(),
1572 file
->getPrintableSource().string());
1574 //printf("%s File Group Entry: %s\n", prefix.string(),
1575 // file->getGroupEntry().toDirName(String8()).string());
1579 String8
AaptGroup::getPrintableSource() const
1581 if (mFiles
.size() > 0) {
1582 // Arbitrarily pull the first source file out of the list.
1583 return mFiles
.valueAt(0)->getPrintableSource();
1586 // Should never hit this case, but to be safe...
1591 // =========================================================================
1592 // =========================================================================
1593 // =========================================================================
1595 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1597 if (mFiles
.indexOfKey(name
) >= 0) {
1598 return ALREADY_EXISTS
;
1600 mFiles
.add(name
, file
);
1604 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1606 if (mDirs
.indexOfKey(name
) >= 0) {
1607 return ALREADY_EXISTS
;
1609 mDirs
.add(name
, dir
);
1613 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1616 String8 remain
= path
;
1618 sp
<AaptDir
> subdir
= this;
1619 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1620 subdir
= subdir
->makeDir(name
);
1623 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1625 return subdir
->mDirs
.valueAt(i
);
1627 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1628 subdir
->mDirs
.add(name
, dir
);
1632 void AaptDir::removeFile(const String8
& name
)
1634 mFiles
.removeItem(name
);
1637 void AaptDir::removeDir(const String8
& name
)
1639 mDirs
.removeItem(name
);
1642 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1644 sp
<AaptGroup
> group
;
1645 if (mFiles
.indexOfKey(leafName
) >= 0) {
1646 group
= mFiles
.valueFor(leafName
);
1648 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1649 mFiles
.add(leafName
, group
);
1652 return group
->addFile(file
);
1655 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1656 const AaptGroupEntry
& kind
, const String8
& resType
,
1657 sp
<FilePathStore
>& fullResPaths
)
1659 Vector
<String8
> fileNames
;
1663 dir
= opendir(srcDir
.string());
1665 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1666 return UNKNOWN_ERROR
;
1670 * Slurp the filenames out of the directory.
1673 struct dirent
* entry
;
1675 entry
= readdir(dir
);
1679 if (isHidden(srcDir
.string(), entry
->d_name
))
1682 String8
name(entry
->d_name
);
1683 fileNames
.add(name
);
1684 // Add fully qualified path for dependency purposes
1685 // if we're collecting them
1686 if (fullResPaths
!= NULL
) {
1687 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1696 * Stash away the files and recursively descend into subdirectories.
1698 const size_t N
= fileNames
.size();
1700 for (i
= 0; i
< N
; i
++) {
1701 String8
pathName(srcDir
);
1704 pathName
.appendPath(fileNames
[i
].string());
1705 type
= getFileType(pathName
.string());
1706 if (type
== kFileTypeDirectory
) {
1708 bool notAdded
= false;
1709 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1710 subdir
= mDirs
.valueFor(fileNames
[i
]);
1712 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1715 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1716 resType
, fullResPaths
);
1717 if (res
< NO_ERROR
) {
1720 if (res
> 0 && notAdded
) {
1721 mDirs
.add(fileNames
[i
], subdir
);
1724 } else if (type
== kFileTypeRegular
) {
1725 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1726 status_t err
= addLeafFile(fileNames
[i
], file
);
1727 if (err
!= NO_ERROR
) {
1734 if (bundle
->getVerbose())
1735 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1742 status_t
AaptDir::validate() const
1744 const size_t NF
= mFiles
.size();
1745 const size_t ND
= mDirs
.size();
1747 for (i
= 0; i
< NF
; i
++) {
1748 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1749 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1750 "Invalid filename. Unable to add.");
1751 return UNKNOWN_ERROR
;
1755 for (j
= i
+1; j
< NF
; j
++) {
1756 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1757 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1758 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1759 "File is case-insensitive equivalent to: %s",
1760 mFiles
.valueAt(j
)->getPrintableSource().string());
1761 return UNKNOWN_ERROR
;
1764 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1765 // (this is mostly caught by the "marked" stuff, below)
1768 for (j
= 0; j
< ND
; j
++) {
1769 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1770 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1771 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1772 "File conflicts with dir from: %s",
1773 mDirs
.valueAt(j
)->getPrintableSource().string());
1774 return UNKNOWN_ERROR
;
1779 for (i
= 0; i
< ND
; i
++) {
1780 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1781 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1782 "Invalid directory name, unable to add.");
1783 return UNKNOWN_ERROR
;
1787 for (j
= i
+1; j
< ND
; j
++) {
1788 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1789 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1790 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1791 "Directory is case-insensitive equivalent to: %s",
1792 mDirs
.valueAt(j
)->getPrintableSource().string());
1793 return UNKNOWN_ERROR
;
1797 status_t err
= mDirs
.valueAt(i
)->validate();
1798 if (err
!= NO_ERROR
) {
1806 void AaptDir::print(const String8
& prefix
) const
1808 const size_t ND
=getDirs().size();
1810 for (i
=0; i
<ND
; i
++) {
1811 getDirs().valueAt(i
)->print(prefix
);
1814 const size_t NF
=getFiles().size();
1815 for (i
=0; i
<NF
; i
++) {
1816 getFiles().valueAt(i
)->print(prefix
);
1820 String8
AaptDir::getPrintableSource() const
1822 if (mFiles
.size() > 0) {
1823 // Arbitrarily pull the first file out of the list as the source dir.
1824 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1826 if (mDirs
.size() > 0) {
1827 // Or arbitrarily pull the first dir out of the list as the source dir.
1828 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1831 // Should never hit this case, but to be safe...
1836 // =========================================================================
1837 // =========================================================================
1838 // =========================================================================
1840 status_t
AaptSymbols::applyJavaSymbols(const sp
<AaptSymbols
>& javaSymbols
)
1842 status_t err
= NO_ERROR
;
1843 size_t N
= javaSymbols
->mSymbols
.size();
1844 for (size_t i
=0; i
<N
; i
++) {
1845 const String8
& name
= javaSymbols
->mSymbols
.keyAt(i
);
1846 const AaptSymbolEntry
& entry
= javaSymbols
->mSymbols
.valueAt(i
);
1847 ssize_t pos
= mSymbols
.indexOfKey(name
);
1849 entry
.sourcePos
.error("Symbol '%s' declared with <java-symbol> not defined\n", name
.string());
1850 err
= UNKNOWN_ERROR
;
1853 //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
1854 // i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
1855 mSymbols
.editValueAt(pos
).isJavaSymbol
= entry
.isJavaSymbol
;
1858 N
= javaSymbols
->mNestedSymbols
.size();
1859 for (size_t i
=0; i
<N
; i
++) {
1860 const String8
& name
= javaSymbols
->mNestedSymbols
.keyAt(i
);
1861 const sp
<AaptSymbols
>& symbols
= javaSymbols
->mNestedSymbols
.valueAt(i
);
1862 ssize_t pos
= mNestedSymbols
.indexOfKey(name
);
1865 pos
.error("Java symbol dir %s not defined\n", name
.string());
1866 err
= UNKNOWN_ERROR
;
1869 //printf("**** applying java symbols in dir %s\n", name.string());
1870 status_t myerr
= mNestedSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
1871 if (myerr
!= NO_ERROR
) {
1879 // =========================================================================
1880 // =========================================================================
1881 // =========================================================================
1883 AaptAssets::AaptAssets()
1884 : AaptDir(String8(), String8()),
1885 mChanged(false), mHaveIncludedAssets(false), mRes(NULL
)
1889 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const {
1892 return mGroupEntries
;
1895 status_t
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1898 return AaptDir::addFile(name
, file
);
1901 sp
<AaptFile
> AaptAssets::addFile(
1902 const String8
& filePath
, const AaptGroupEntry
& entry
,
1903 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1904 const String8
& resType
)
1906 sp
<AaptDir
> dir
= this;
1907 sp
<AaptGroup
> group
;
1909 String8 root
, remain(filePath
), partialPath
;
1910 while (remain
.length() > 0) {
1911 root
= remain
.walkPath(&remain
);
1912 partialPath
.appendPath(root
);
1914 const String8
rootStr(root
);
1916 if (remain
.length() == 0) {
1917 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1919 group
= dir
->getFiles().valueAt(i
);
1921 group
= new AaptGroup(rootStr
, filePath
);
1922 status_t res
= dir
->addFile(rootStr
, group
);
1923 if (res
!= NO_ERROR
) {
1927 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1928 status_t res
= group
->addFile(file
);
1929 if (res
!= NO_ERROR
) {
1935 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1937 dir
= dir
->getDirs().valueAt(i
);
1939 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1940 status_t res
= dir
->addDir(rootStr
, subdir
);
1941 if (res
!= NO_ERROR
) {
1949 mGroupEntries
.add(entry
);
1950 if (outGroup
) *outGroup
= group
;
1954 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1955 const sp
<AaptFile
>& file
, const String8
& resType
)
1957 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1958 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1959 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1960 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1963 subdir
->addFile(leafName
, grr
);
1967 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1972 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1973 const size_t dirCount
=resDirs
.size();
1974 sp
<AaptAssets
> current
= this;
1976 const int N
= bundle
->getFileSpecCount();
1979 * If a package manifest was specified, include that first.
1981 if (bundle
->getAndroidManifestFile() != NULL
) {
1982 // place at root of zip.
1983 String8
srcFile(bundle
->getAndroidManifestFile());
1984 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1990 * If a directory of custom assets was supplied, slurp 'em up.
1992 if (bundle
->getAssetSourceDir()) {
1993 const char* assetDir
= bundle
->getAssetSourceDir();
1995 FileType type
= getFileType(assetDir
);
1996 if (type
== kFileTypeNonexistent
) {
1997 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1998 return UNKNOWN_ERROR
;
2000 if (type
!= kFileTypeDirectory
) {
2001 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2002 return UNKNOWN_ERROR
;
2005 String8
assetRoot(assetDir
);
2006 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
2007 AaptGroupEntry group
;
2008 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
2009 String8(), mFullAssetPaths
);
2015 mGroupEntries
.add(group
);
2017 totalCount
+= count
;
2019 if (bundle
->getVerbose())
2020 printf("Found %d custom asset file%s in %s\n",
2021 count
, (count
==1) ? "" : "s", assetDir
);
2025 * If a directory of resource-specific assets was supplied, slurp 'em up.
2027 for (size_t i
=0; i
<dirCount
; i
++) {
2028 const char *res
= resDirs
[i
];
2030 type
= getFileType(res
);
2031 if (type
== kFileTypeNonexistent
) {
2032 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
2033 return UNKNOWN_ERROR
;
2035 if (type
== kFileTypeDirectory
) {
2037 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
2038 current
->setOverlay(nextOverlay
);
2039 current
= nextOverlay
;
2040 current
->setFullResPaths(mFullResPaths
);
2042 count
= current
->slurpResourceTree(bundle
, String8(res
));
2048 totalCount
+= count
;
2051 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
2052 return UNKNOWN_ERROR
;
2058 * Now do any additional raw files.
2060 for (int arg
=0; arg
<N
; arg
++) {
2061 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
2063 FileType type
= getFileType(assetDir
);
2064 if (type
== kFileTypeNonexistent
) {
2065 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
2066 return UNKNOWN_ERROR
;
2068 if (type
!= kFileTypeDirectory
) {
2069 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
2070 return UNKNOWN_ERROR
;
2073 String8
assetRoot(assetDir
);
2075 if (bundle
->getVerbose())
2076 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
2079 * Do a recursive traversal of subdir tree. We don't make any
2080 * guarantees about ordering, so we're okay with an inorder search
2081 * using whatever order the OS happens to hand back to us.
2083 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
2085 /* failure; report error and remove archive */
2089 totalCount
+= count
;
2091 if (bundle
->getVerbose())
2092 printf("Found %d asset file%s in %s\n",
2093 count
, (count
==1) ? "" : "s", assetDir
);
2097 if (count
!= NO_ERROR
) {
2102 count
= filter(bundle
);
2103 if (count
!= NO_ERROR
) {
2112 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
2113 const AaptGroupEntry
& kind
,
2114 const String8
& resType
,
2115 sp
<FilePathStore
>& fullResPaths
)
2117 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
2119 mGroupEntries
.add(kind
);
2125 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
2129 DIR* dir
= opendir(srcDir
.string());
2131 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
2132 return UNKNOWN_ERROR
;
2138 * Run through the directory, looking for dirs that match the
2142 struct dirent
* entry
= readdir(dir
);
2143 if (entry
== NULL
) {
2147 if (isHidden(srcDir
.string(), entry
->d_name
)) {
2151 String8
subdirName(srcDir
);
2152 subdirName
.appendPath(entry
->d_name
);
2154 AaptGroupEntry group
;
2156 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
2158 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2164 if (bundle
->getMaxResVersion() != NULL
&& group
.getVersionString().length() != 0) {
2165 int maxResInt
= atoi(bundle
->getMaxResVersion());
2166 const char *verString
= group
.getVersionString().string();
2167 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2168 if (dirVersionInt
> maxResInt
) {
2169 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2174 FileType type
= getFileType(subdirName
.string());
2176 if (type
== kFileTypeDirectory
) {
2177 sp
<AaptDir
> dir
= makeDir(resType
);
2178 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2179 resType
, mFullResPaths
);
2185 mGroupEntries
.add(group
);
2189 // Only add this directory if we don't already have a resource dir
2190 // for the current type. This ensures that we only add the dir once
2192 sp
<AaptDir
> rdir
= resDir(resType
);
2197 if (bundle
->getVerbose()) {
2198 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2214 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2217 SortedVector
<AaptGroupEntry
> entries
;
2219 ZipFile
* zip
= new ZipFile
;
2220 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2221 if (err
!= NO_ERROR
) {
2222 fprintf(stderr
, "error opening zip file %s\n", filename
);
2228 const int N
= zip
->getNumEntries();
2229 for (int i
=0; i
<N
; i
++) {
2230 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2231 if (entry
->getDeleted()) {
2235 String8
entryName(entry
->getFileName());
2237 String8 dirName
= entryName
.getPathDir();
2238 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2241 AaptGroupEntry kind
;
2244 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2245 // these are the resources, pull their type out of the directory name
2246 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2248 // these are untyped and don't have an AaptGroupEntry
2250 if (entries
.indexOf(kind
) < 0) {
2252 mGroupEntries
.add(kind
);
2255 // use the one from the zip file if they both exist.
2256 dir
->removeFile(entryName
.getPathLeaf());
2258 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2259 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2260 if (err
!= NO_ERROR
) {
2261 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2265 file
->setCompressionMethod(entry
->getCompressionMethod());
2268 if (entryName
== "AndroidManifest.xml") {
2269 printf("AndroidManifest.xml\n");
2271 printf("\n\nfile: %s\n", entryName
.string());
2274 size_t len
= entry
->getUncompressedLen();
2275 void* data
= zip
->uncompress(entry
);
2276 void* buf
= file
->editData(len
);
2277 memcpy(buf
, data
, len
);
2281 const unsigned char* p
= (unsigned char*)data
;
2282 const unsigned char* end
= p
+len
;
2284 for (int i
=0; i
<32 && p
< end
; i
++) {
2285 printf("0x%03x ", i
*0x10 + OFF
);
2286 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2287 printf(" %02x", *p
);
2304 status_t
AaptAssets::filter(Bundle
* bundle
)
2306 ResourceFilter reqFilter
;
2307 status_t err
= reqFilter
.parse(bundle
->getConfigurations());
2308 if (err
!= NO_ERROR
) {
2312 ResourceFilter prefFilter
;
2313 err
= prefFilter
.parse(bundle
->getPreferredConfigurations());
2314 if (err
!= NO_ERROR
) {
2318 if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) {
2322 if (bundle
->getVerbose()) {
2323 if (!reqFilter
.isEmpty()) {
2324 printf("Applying required filter: %s\n",
2325 bundle
->getConfigurations());
2327 if (!prefFilter
.isEmpty()) {
2328 printf("Applying preferred filter: %s\n",
2329 bundle
->getPreferredConfigurations());
2333 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2334 const size_t ND
= resdirs
.size();
2335 for (size_t i
=0; i
<ND
; i
++) {
2336 const sp
<AaptDir
>& dir
= resdirs
.itemAt(i
);
2337 if (dir
->getLeaf() == kValuesDir
) {
2338 // The "value" dir is special since a single file defines
2339 // multiple resources, so we can not do filtering on the
2340 // files themselves.
2343 if (dir
->getLeaf() == kMipmapDir
) {
2344 // We also skip the "mipmap" directory, since the point of this
2345 // is to include all densities without stripping. If you put
2346 // other configurations in here as well they won't be stripped
2347 // either... So don't do that. Seriously. What is wrong with you?
2351 const size_t NG
= dir
->getFiles().size();
2352 for (size_t j
=0; j
<NG
; j
++) {
2353 sp
<AaptGroup
> grp
= dir
->getFiles().valueAt(j
);
2355 // First remove any configurations we know we don't need.
2356 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2357 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2358 if (k
== 0 && grp
->getFiles().size() == 1) {
2359 // If this is the only file left, we need to keep it.
2360 // Otherwise the resource IDs we are using will be inconsistent
2361 // with what we get when not stripping. Sucky, but at least
2362 // for now we can rely on the back-end doing another filtering
2363 // pass to take this out and leave us with this resource name
2364 // containing no entries.
2367 if (file
->getPath().getPathExtension() == ".xml") {
2368 // We can't remove .xml files at this point, because when
2369 // we parse them they may add identifier resources, so
2370 // removing them can cause our resource identifiers to
2371 // become inconsistent.
2374 const ResTable_config
& config(file
->getGroupEntry().toParams());
2375 if (!reqFilter
.match(config
)) {
2376 if (bundle
->getVerbose()) {
2377 printf("Pruning unneeded resource: %s\n",
2378 file
->getPrintableSource().string());
2385 // Quick check: no preferred filters, nothing more to do.
2386 if (prefFilter
.isEmpty()) {
2390 // Now deal with preferred configurations.
2391 for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) {
2392 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) {
2393 sp
<AaptFile
> file
= grp
->getFiles().valueAt(k
);
2394 if (k
== 0 && grp
->getFiles().size() == 1) {
2395 // If this is the only file left, we need to keep it.
2396 // Otherwise the resource IDs we are using will be inconsistent
2397 // with what we get when not stripping. Sucky, but at least
2398 // for now we can rely on the back-end doing another filtering
2399 // pass to take this out and leave us with this resource name
2400 // containing no entries.
2403 if (file
->getPath().getPathExtension() == ".xml") {
2404 // We can't remove .xml files at this point, because when
2405 // we parse them they may add identifier resources, so
2406 // removing them can cause our resource identifiers to
2407 // become inconsistent.
2410 const ResTable_config
& config(file
->getGroupEntry().toParams());
2411 if (!prefFilter
.match(axis
, config
)) {
2412 // This is a resource we would prefer not to have. Check
2413 // to see if have a similar variation that we would like
2414 // to have and, if so, we can drop it.
2415 for (size_t m
=0; m
<grp
->getFiles().size(); m
++) {
2416 if (m
== k
) continue;
2417 sp
<AaptFile
> mfile
= grp
->getFiles().valueAt(m
);
2418 const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams());
2419 if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) {
2420 if (prefFilter
.match(axis
, mconfig
)) {
2421 if (bundle
->getVerbose()) {
2422 printf("Pruning unneeded resource: %s\n",
2423 file
->getPrintableSource().string());
2440 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2442 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2444 sym
= new AaptSymbols();
2445 mSymbols
.add(name
, sym
);
2450 sp
<AaptSymbols
> AaptAssets::getJavaSymbolsFor(const String8
& name
)
2452 sp
<AaptSymbols
> sym
= mJavaSymbols
.valueFor(name
);
2454 sym
= new AaptSymbols();
2455 mJavaSymbols
.add(name
, sym
);
2460 status_t
AaptAssets::applyJavaSymbols()
2462 size_t N
= mJavaSymbols
.size();
2463 for (size_t i
=0; i
<N
; i
++) {
2464 const String8
& name
= mJavaSymbols
.keyAt(i
);
2465 const sp
<AaptSymbols
>& symbols
= mJavaSymbols
.valueAt(i
);
2466 ssize_t pos
= mSymbols
.indexOfKey(name
);
2469 pos
.error("Java symbol dir %s not defined\n", name
.string());
2470 return UNKNOWN_ERROR
;
2472 //printf("**** applying java symbols in dir %s\n", name.string());
2473 status_t err
= mSymbols
.valueAt(pos
)->applyJavaSymbols(symbols
);
2474 if (err
!= NO_ERROR
) {
2482 bool AaptAssets::isJavaSymbol(const AaptSymbolEntry
& sym
, bool includePrivate
) const {
2483 //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
2484 // sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
2485 // sym.isJavaSymbol ? 1 : 0);
2486 if (!mHavePrivateSymbols
) return true;
2487 if (sym
.isPublic
) return true;
2488 if (includePrivate
&& sym
.isJavaSymbol
) return true;
2492 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2494 if (!mHaveIncludedAssets
) {
2495 // Add in all includes.
2496 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2497 const size_t N
=incl
.size();
2498 for (size_t i
=0; i
<N
; i
++) {
2499 if (bundle
->getVerbose())
2500 printf("Including resources from package: %s\n", incl
[i
]);
2501 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2502 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2504 return UNKNOWN_ERROR
;
2507 mHaveIncludedAssets
= true;
2513 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2515 const ResTable
& res
= getIncludedResources();
2517 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2520 const ResTable
& AaptAssets::getIncludedResources() const
2522 return mIncludedAssets
.getResources(false);
2525 void AaptAssets::print(const String8
& prefix
) const
2527 String8
innerPrefix(prefix
);
2528 innerPrefix
.append(" ");
2529 String8
innerInnerPrefix(innerPrefix
);
2530 innerInnerPrefix
.append(" ");
2531 printf("%sConfigurations:\n", prefix
.string());
2532 const size_t N
=mGroupEntries
.size();
2533 for (size_t i
=0; i
<N
; i
++) {
2534 String8 cname
= mGroupEntries
.itemAt(i
).toDirName(String8());
2535 printf("%s %s\n", prefix
.string(),
2536 cname
!= "" ? cname
.string() : "(default)");
2539 printf("\n%sFiles:\n", prefix
.string());
2540 AaptDir::print(innerPrefix
);
2542 printf("\n%sResource Dirs:\n", prefix
.string());
2543 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2544 const size_t NR
= resdirs
.size();
2545 for (size_t i
=0; i
<NR
; i
++) {
2546 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2547 printf("%s Type %s\n", prefix
.string(), d
->getLeaf().string());
2548 d
->print(innerInnerPrefix
);
2552 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const
2554 const Vector
<sp
<AaptDir
> >& resdirs
= mResDirs
;
2555 const size_t N
= resdirs
.size();
2556 for (size_t i
=0; i
<N
; i
++) {
2557 const sp
<AaptDir
>& d
= resdirs
.itemAt(i
);
2558 if (d
->getLeaf() == name
) {
2566 valid_symbol_name(const String8
& symbol
)
2568 static char const * const KEYWORDS
[] = {
2569 "abstract", "assert", "boolean", "break",
2570 "byte", "case", "catch", "char", "class", "const", "continue",
2571 "default", "do", "double", "else", "enum", "extends", "final",
2572 "finally", "float", "for", "goto", "if", "implements", "import",
2573 "instanceof", "int", "interface", "long", "native", "new", "package",
2574 "private", "protected", "public", "return", "short", "static",
2575 "strictfp", "super", "switch", "synchronized", "this", "throw",
2576 "throws", "transient", "try", "void", "volatile", "while",
2577 "true", "false", "null",
2580 const char*const* k
= KEYWORDS
;
2581 const char*const s
= symbol
.string();
2583 if (0 == strcmp(s
, *k
)) {