2 // Copyright 2006 The Android Open Source Project
5 #include "AaptAssets.h"
8 #include <utils/misc.h>
9 #include <utils/SortedVector.h>
15 static const char* kDefaultLocale
= "default";
16 static const char* kWildcardName
= "any";
17 static const char* kAssetDir
= "assets";
18 static const char* kResourceDir
= "res";
19 static const char* kInvalidChars
= "/\\:";
20 static const size_t kMaxAssetFileName
= 100;
22 static const String8
kResString(kResourceDir
);
25 * Names of asset files must meet the following criteria:
27 * - the filename length must be less than kMaxAssetFileName bytes long
28 * (and can't be empty)
29 * - all characters must be 7-bit printable ASCII
30 * - none of { '/' '\\' ':' }
32 * Pass in just the filename, not the full path.
34 static bool validateFileName(const char* fileName
)
36 const char* cp
= fileName
;
40 if ((*cp
& 0x80) != 0)
41 return false; // reject high ASCII
42 if (*cp
< 0x20 || *cp
>= 0x7f)
43 return false; // reject control chars and 0x7f
44 if (strchr(kInvalidChars
, *cp
) != NULL
)
45 return false; // reject path sep chars
50 if (len
< 1 || len
> kMaxAssetFileName
)
51 return false; // reject empty or too long
56 static bool isHidden(const char *root
, const char *path
)
58 const char *ext
= NULL
;
59 const char *type
= NULL
;
61 // Skip all hidden files.
63 // Skip ., .. and .svn but don't chatter about it.
64 if (strcmp(path
, ".") == 0
65 || strcmp(path
, "..") == 0
66 || strcmp(path
, ".svn") == 0) {
70 } else if (path
[0] == '_') {
71 // skip directories starting with _ (don't chatter about it)
72 String8
subdirName(root
);
73 subdirName
.appendPath(path
);
74 if (getFileType(subdirName
.string()) == kFileTypeDirectory
) {
77 } else if (strcmp(path
, "CVS") == 0) {
78 // Skip CVS but don't chatter about it.
80 } else if (strcasecmp(path
, "thumbs.db") == 0
81 || strcasecmp(path
, "picasa.ini") == 0) {
82 // Skip suspected image indexes files.
84 } else if (path
[strlen(path
)-1] == '~') {
85 // Skip suspected emacs backup files.
87 } else if ((ext
= strrchr(path
, '.')) != NULL
&& strcmp(ext
, ".scc") == 0) {
88 // Skip VisualSourceSafe files and don't chatter about it
91 // Let everything else through.
95 /* If we get this far, "type" should be set and the file
98 String8
subdirName(root
);
99 subdirName
.appendPath(path
);
100 fprintf(stderr
, " (skipping %s %s '%s')\n", type
,
101 getFileType(subdirName
.string())==kFileTypeDirectory
? "dir":"file",
102 subdirName
.string());
107 // =========================================================================
108 // =========================================================================
109 // =========================================================================
112 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
)
114 ResTable_config config
;
117 if (getMccName(part
.string(), &config
)) {
124 if (getMncName(part
.string(), &config
)) {
131 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
132 *axis
= AXIS_LANGUAGE
;
133 *value
= part
[1] << 8 | part
[0];
137 // locale - language_REGION
138 if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1])
139 && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) {
140 *axis
= AXIS_LANGUAGE
;
141 *value
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]);
145 // smallest screen dp width
146 if (getSmallestScreenWidthDpName(part
.string(), &config
)) {
147 *axis
= AXIS_SMALLESTSCREENWIDTHDP
;
148 *value
= config
.smallestScreenWidthDp
;
153 if (getScreenWidthDpName(part
.string(), &config
)) {
154 *axis
= AXIS_SCREENWIDTHDP
;
155 *value
= config
.screenWidthDp
;
160 if (getScreenHeightDpName(part
.string(), &config
)) {
161 *axis
= AXIS_SCREENHEIGHTDP
;
162 *value
= config
.screenHeightDp
;
166 // screen layout size
167 if (getScreenLayoutSizeName(part
.string(), &config
)) {
168 *axis
= AXIS_SCREENLAYOUTSIZE
;
169 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
173 // screen layout long
174 if (getScreenLayoutLongName(part
.string(), &config
)) {
175 *axis
= AXIS_SCREENLAYOUTLONG
;
176 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
181 if (getOrientationName(part
.string(), &config
)) {
182 *axis
= AXIS_ORIENTATION
;
183 *value
= config
.orientation
;
188 if (getUiModeTypeName(part
.string(), &config
)) {
189 *axis
= AXIS_UIMODETYPE
;
190 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
);
195 if (getUiModeNightName(part
.string(), &config
)) {
196 *axis
= AXIS_UIMODENIGHT
;
197 *value
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
);
202 if (getDensityName(part
.string(), &config
)) {
203 *axis
= AXIS_DENSITY
;
204 *value
= config
.density
;
209 if (getTouchscreenName(part
.string(), &config
)) {
210 *axis
= AXIS_TOUCHSCREEN
;
211 *value
= config
.touchscreen
;
216 if (getKeysHiddenName(part
.string(), &config
)) {
217 *axis
= AXIS_KEYSHIDDEN
;
218 *value
= config
.inputFlags
;
223 if (getKeyboardName(part
.string(), &config
)) {
224 *axis
= AXIS_KEYBOARD
;
225 *value
= config
.keyboard
;
230 if (getNavHiddenName(part
.string(), &config
)) {
231 *axis
= AXIS_NAVHIDDEN
;
232 *value
= config
.inputFlags
;
237 if (getNavigationName(part
.string(), &config
)) {
238 *axis
= AXIS_NAVIGATION
;
239 *value
= config
.navigation
;
244 if (getScreenSizeName(part
.string(), &config
)) {
245 *axis
= AXIS_SCREENSIZE
;
246 *value
= config
.screenSize
;
251 if (getVersionName(part
.string(), &config
)) {
252 *axis
= AXIS_VERSION
;
253 *value
= config
.version
;
261 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
263 Vector
<String8
> parts
;
265 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
266 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
;
267 String8 uiModeType
, uiModeNight
, smallestwidthdp
, widthdp
, heightdp
;
271 while (NULL
!= (q
= strchr(p
, '-'))) {
275 //printf("part: %s\n", parts[parts.size()-1].string());
281 //printf("part: %s\n", parts[parts.size()-1].string());
283 const int N
= parts
.size();
285 String8 part
= parts
[index
];
288 if (!isValidResourceType(part
)) {
300 if (getMccName(part
.string())) {
309 //printf("not mcc: %s\n", part.string());
313 if (getMncName(part
.string())) {
322 //printf("not mcc: %s\n", part.string());
326 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
335 //printf("not language: %s\n", part.string());
340 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
343 loc
+= part
.string() + 1;
351 //printf("not region: %s\n", part.string());
354 if (getSmallestScreenWidthDpName(part
.string())) {
355 smallestwidthdp
= part
;
363 //printf("not smallest screen width dp: %s\n", part.string());
366 if (getScreenWidthDpName(part
.string())) {
375 //printf("not screen width dp: %s\n", part.string());
378 if (getScreenHeightDpName(part
.string())) {
387 //printf("not screen height dp: %s\n", part.string());
390 if (getScreenLayoutSizeName(part
.string())) {
399 //printf("not screen layout size: %s\n", part.string());
402 if (getScreenLayoutLongName(part
.string())) {
411 //printf("not screen layout long: %s\n", part.string());
415 if (getOrientationName(part
.string())) {
424 //printf("not orientation: %s\n", part.string());
428 if (getUiModeTypeName(part
.string())) {
437 //printf("not ui mode type: %s\n", part.string());
441 if (getUiModeNightName(part
.string())) {
450 //printf("not ui mode night: %s\n", part.string());
454 if (getDensityName(part
.string())) {
463 //printf("not density: %s\n", part.string());
467 if (getTouchscreenName(part
.string())) {
476 //printf("not touchscreen: %s\n", part.string());
480 if (getKeysHiddenName(part
.string())) {
489 //printf("not keysHidden: %s\n", part.string());
493 if (getKeyboardName(part
.string())) {
502 //printf("not keyboard: %s\n", part.string());
506 if (getNavHiddenName(part
.string())) {
515 //printf("not navHidden: %s\n", part.string());
518 if (getNavigationName(part
.string())) {
527 //printf("not navigation: %s\n", part.string());
530 if (getScreenSizeName(part
.string())) {
539 //printf("not screen size: %s\n", part.string());
542 if (getVersionName(part
.string())) {
551 //printf("not version: %s\n", part.string());
554 // if there are extra parts, it doesn't match
561 this->screenLayoutSize
= layoutsize
;
562 this->screenLayoutLong
= layoutlong
;
563 this->smallestScreenWidthDp
= smallestwidthdp
;
564 this->screenWidthDp
= widthdp
;
565 this->screenHeightDp
= heightdp
;
566 this->orientation
= orient
;
567 this->uiModeType
= uiModeType
;
568 this->uiModeNight
= uiModeNight
;
570 this->touchscreen
= touch
;
571 this->keysHidden
= keysHidden
;
572 this->keyboard
= key
;
573 this->navHidden
= navHidden
;
574 this->navigation
= nav
;
575 this->screenSize
= size
;
576 this->version
= vers
;
578 // what is this anyway?
585 AaptGroupEntry::toString() const
587 String8 s
= this->mcc
;
593 s
+= smallestScreenWidthDp
;
599 s
+= screenLayoutSize
;
601 s
+= screenLayoutLong
;
603 s
+= this->orientation
;
628 AaptGroupEntry::toDirName(const String8
& resType
) const
631 if (this->mcc
!= "") {
635 if (this->mnc
!= "") {
639 if (this->locale
!= "") {
643 if (this->smallestScreenWidthDp
!= "") {
645 s
+= smallestScreenWidthDp
;
647 if (this->screenWidthDp
!= "") {
651 if (this->screenHeightDp
!= "") {
655 if (this->screenLayoutSize
!= "") {
657 s
+= screenLayoutSize
;
659 if (this->screenLayoutLong
!= "") {
661 s
+= screenLayoutLong
;
663 if (this->orientation
!= "") {
667 if (this->uiModeType
!= "") {
671 if (this->uiModeNight
!= "") {
675 if (this->density
!= "") {
679 if (this->touchscreen
!= "") {
683 if (this->keysHidden
!= "") {
687 if (this->keyboard
!= "") {
691 if (this->navHidden
!= "") {
695 if (this->navigation
!= "") {
699 if (this->screenSize
!= "") {
703 if (this->version
!= "") {
711 bool AaptGroupEntry::getMccName(const char* name
,
712 ResTable_config
* out
)
714 if (strcmp(name
, kWildcardName
) == 0) {
715 if (out
) out
->mcc
= 0;
718 const char* c
= name
;
719 if (tolower(*c
) != 'm') return false;
721 if (tolower(*c
) != 'c') return false;
723 if (tolower(*c
) != 'c') return false;
728 while (*c
>= '0' && *c
<= '9') {
731 if (*c
!= 0) return false;
732 if (c
-val
!= 3) return false;
736 if (out
) out
->mcc
= d
;
743 bool AaptGroupEntry::getMncName(const char* name
,
744 ResTable_config
* out
)
746 if (strcmp(name
, kWildcardName
) == 0) {
747 if (out
) out
->mcc
= 0;
750 const char* c
= name
;
751 if (tolower(*c
) != 'm') return false;
753 if (tolower(*c
) != 'n') return false;
755 if (tolower(*c
) != 'c') return false;
760 while (*c
>= '0' && *c
<= '9') {
763 if (*c
!= 0) return false;
764 if (c
-val
== 0 || c
-val
> 3) return false;
767 out
->mnc
= atoi(val
);
774 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
777 * TODO: Should insist that the first two letters are lower case, and the
778 * second two are upper.
780 bool AaptGroupEntry::getLocaleName(const char* fileName
,
781 ResTable_config
* out
)
783 if (strcmp(fileName
, kWildcardName
) == 0
784 || strcmp(fileName
, kDefaultLocale
) == 0) {
786 out
->language
[0] = 0;
787 out
->language
[1] = 0;
794 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
796 out
->language
[0] = fileName
[0];
797 out
->language
[1] = fileName
[1];
804 if (strlen(fileName
) == 5 &&
805 isalpha(fileName
[0]) &&
806 isalpha(fileName
[1]) &&
807 fileName
[2] == '-' &&
808 isalpha(fileName
[3]) &&
809 isalpha(fileName
[4])) {
811 out
->language
[0] = fileName
[0];
812 out
->language
[1] = fileName
[1];
813 out
->country
[0] = fileName
[3];
814 out
->country
[1] = fileName
[4];
822 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
823 ResTable_config
* out
)
825 if (strcmp(name
, kWildcardName
) == 0) {
826 if (out
) out
->screenLayout
=
827 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
828 | ResTable_config::SCREENSIZE_ANY
;
830 } else if (strcmp(name
, "small") == 0) {
831 if (out
) out
->screenLayout
=
832 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
833 | ResTable_config::SCREENSIZE_SMALL
;
835 } else if (strcmp(name
, "normal") == 0) {
836 if (out
) out
->screenLayout
=
837 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
838 | ResTable_config::SCREENSIZE_NORMAL
;
840 } else if (strcmp(name
, "large") == 0) {
841 if (out
) out
->screenLayout
=
842 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
843 | ResTable_config::SCREENSIZE_LARGE
;
845 } else if (strcmp(name
, "xlarge") == 0) {
846 if (out
) out
->screenLayout
=
847 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
848 | ResTable_config::SCREENSIZE_XLARGE
;
855 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
856 ResTable_config
* out
)
858 if (strcmp(name
, kWildcardName
) == 0) {
859 if (out
) out
->screenLayout
=
860 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
861 | ResTable_config::SCREENLONG_ANY
;
863 } else if (strcmp(name
, "long") == 0) {
864 if (out
) out
->screenLayout
=
865 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
866 | ResTable_config::SCREENLONG_YES
;
868 } else if (strcmp(name
, "notlong") == 0) {
869 if (out
) out
->screenLayout
=
870 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
871 | ResTable_config::SCREENLONG_NO
;
878 bool AaptGroupEntry::getOrientationName(const char* name
,
879 ResTable_config
* out
)
881 if (strcmp(name
, kWildcardName
) == 0) {
882 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
884 } else if (strcmp(name
, "port") == 0) {
885 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
887 } else if (strcmp(name
, "land") == 0) {
888 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
890 } else if (strcmp(name
, "square") == 0) {
891 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
898 bool AaptGroupEntry::getUiModeTypeName(const char* name
,
899 ResTable_config
* out
)
901 if (strcmp(name
, kWildcardName
) == 0) {
902 if (out
) out
->uiMode
=
903 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
904 | ResTable_config::UI_MODE_TYPE_ANY
;
906 } else if (strcmp(name
, "desk") == 0) {
907 if (out
) out
->uiMode
=
908 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
909 | ResTable_config::UI_MODE_TYPE_DESK
;
911 } else if (strcmp(name
, "car") == 0) {
912 if (out
) out
->uiMode
=
913 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
914 | ResTable_config::UI_MODE_TYPE_CAR
;
916 } else if (strcmp(name
, "television") == 0) {
917 if (out
) out
->uiMode
=
918 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
)
919 | ResTable_config::UI_MODE_TYPE_TELEVISION
;
926 bool AaptGroupEntry::getUiModeNightName(const char* name
,
927 ResTable_config
* out
)
929 if (strcmp(name
, kWildcardName
) == 0) {
930 if (out
) out
->uiMode
=
931 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
932 | ResTable_config::UI_MODE_NIGHT_ANY
;
934 } else if (strcmp(name
, "night") == 0) {
935 if (out
) out
->uiMode
=
936 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
937 | ResTable_config::UI_MODE_NIGHT_YES
;
939 } else if (strcmp(name
, "notnight") == 0) {
940 if (out
) out
->uiMode
=
941 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
)
942 | ResTable_config::UI_MODE_NIGHT_NO
;
949 bool AaptGroupEntry::getDensityName(const char* name
,
950 ResTable_config
* out
)
952 if (strcmp(name
, kWildcardName
) == 0) {
953 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
957 if (strcmp(name
, "nodpi") == 0) {
958 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
962 if (strcmp(name
, "ldpi") == 0) {
963 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
967 if (strcmp(name
, "mdpi") == 0) {
968 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
972 if (strcmp(name
, "tvdpi") == 0) {
973 if (out
) out
->density
= ResTable_config::DENSITY_TV
;
977 if (strcmp(name
, "hdpi") == 0) {
978 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
982 if (strcmp(name
, "xhdpi") == 0) {
983 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
*2;
987 char* c
= (char*)name
;
988 while (*c
>= '0' && *c
<= '9') {
992 // check that we have 'dpi' after the last digit.
993 if (toupper(c
[0]) != 'D' ||
994 toupper(c
[1]) != 'P' ||
995 toupper(c
[2]) != 'I' ||
1000 // temporarily replace the first letter with \0 to
1009 if (out
) out
->density
= d
;
1016 bool AaptGroupEntry::getTouchscreenName(const char* name
,
1017 ResTable_config
* out
)
1019 if (strcmp(name
, kWildcardName
) == 0) {
1020 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
1022 } else if (strcmp(name
, "notouch") == 0) {
1023 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
1025 } else if (strcmp(name
, "stylus") == 0) {
1026 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
1028 } else if (strcmp(name
, "finger") == 0) {
1029 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
1036 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
1037 ResTable_config
* out
)
1041 if (strcmp(name
, kWildcardName
) == 0) {
1042 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1043 value
= ResTable_config::KEYSHIDDEN_ANY
;
1044 } else if (strcmp(name
, "keysexposed") == 0) {
1045 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1046 value
= ResTable_config::KEYSHIDDEN_NO
;
1047 } else if (strcmp(name
, "keyshidden") == 0) {
1048 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1049 value
= ResTable_config::KEYSHIDDEN_YES
;
1050 } else if (strcmp(name
, "keyssoft") == 0) {
1051 mask
= ResTable_config::MASK_KEYSHIDDEN
;
1052 value
= ResTable_config::KEYSHIDDEN_SOFT
;
1056 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1063 bool AaptGroupEntry::getKeyboardName(const char* name
,
1064 ResTable_config
* out
)
1066 if (strcmp(name
, kWildcardName
) == 0) {
1067 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
1069 } else if (strcmp(name
, "nokeys") == 0) {
1070 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
1072 } else if (strcmp(name
, "qwerty") == 0) {
1073 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
1075 } else if (strcmp(name
, "12key") == 0) {
1076 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
1083 bool AaptGroupEntry::getNavHiddenName(const char* name
,
1084 ResTable_config
* out
)
1088 if (strcmp(name
, kWildcardName
) == 0) {
1089 mask
= ResTable_config::MASK_NAVHIDDEN
;
1090 value
= ResTable_config::NAVHIDDEN_ANY
;
1091 } else if (strcmp(name
, "navexposed") == 0) {
1092 mask
= ResTable_config::MASK_NAVHIDDEN
;
1093 value
= ResTable_config::NAVHIDDEN_NO
;
1094 } else if (strcmp(name
, "navhidden") == 0) {
1095 mask
= ResTable_config::MASK_NAVHIDDEN
;
1096 value
= ResTable_config::NAVHIDDEN_YES
;
1100 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
1107 bool AaptGroupEntry::getNavigationName(const char* name
,
1108 ResTable_config
* out
)
1110 if (strcmp(name
, kWildcardName
) == 0) {
1111 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
1113 } else if (strcmp(name
, "nonav") == 0) {
1114 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
1116 } else if (strcmp(name
, "dpad") == 0) {
1117 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
1119 } else if (strcmp(name
, "trackball") == 0) {
1120 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
1122 } else if (strcmp(name
, "wheel") == 0) {
1123 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
1130 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
)
1132 if (strcmp(name
, kWildcardName
) == 0) {
1134 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
1135 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
1140 const char* x
= name
;
1141 while (*x
>= '0' && *x
<= '9') x
++;
1142 if (x
== name
|| *x
!= 'x') return false;
1143 String8
xName(name
, x
-name
);
1147 while (*y
>= '0' && *y
<= '9') y
++;
1148 if (y
== name
|| *y
!= 0) return false;
1149 String8
yName(x
, y
-x
);
1151 uint16_t w
= (uint16_t)atoi(xName
.string());
1152 uint16_t h
= (uint16_t)atoi(yName
.string());
1158 out
->screenWidth
= w
;
1159 out
->screenHeight
= h
;
1165 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
)
1167 if (strcmp(name
, kWildcardName
) == 0) {
1169 out
->smallestScreenWidthDp
= out
->SCREENWIDTH_ANY
;
1174 if (*name
!= 's') return false;
1176 if (*name
!= 'w') return false;
1178 const char* x
= name
;
1179 while (*x
>= '0' && *x
<= '9') x
++;
1180 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1181 String8
xName(name
, x
-name
);
1184 out
->smallestScreenWidthDp
= (uint16_t)atoi(xName
.string());
1190 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
)
1192 if (strcmp(name
, kWildcardName
) == 0) {
1194 out
->screenWidthDp
= out
->SCREENWIDTH_ANY
;
1199 if (*name
!= 'w') return false;
1201 const char* x
= name
;
1202 while (*x
>= '0' && *x
<= '9') x
++;
1203 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1204 String8
xName(name
, x
-name
);
1207 out
->screenWidthDp
= (uint16_t)atoi(xName
.string());
1213 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
)
1215 if (strcmp(name
, kWildcardName
) == 0) {
1217 out
->screenHeightDp
= out
->SCREENWIDTH_ANY
;
1222 if (*name
!= 'h') return false;
1224 const char* x
= name
;
1225 while (*x
>= '0' && *x
<= '9') x
++;
1226 if (x
== name
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false;
1227 String8
xName(name
, x
-name
);
1230 out
->screenHeightDp
= (uint16_t)atoi(xName
.string());
1236 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
)
1238 if (strcmp(name
, kWildcardName
) == 0) {
1240 out
->sdkVersion
= out
->SDKVERSION_ANY
;
1241 out
->minorVersion
= out
->MINORVERSION_ANY
;
1251 const char* s
= name
;
1252 while (*s
>= '0' && *s
<= '9') s
++;
1253 if (s
== name
|| *s
!= 0) return false;
1254 String8
sdkName(name
, s
-name
);
1257 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
1258 out
->minorVersion
= 0;
1264 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1266 int v
= mcc
.compare(o
.mcc
);
1267 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1268 if (v
== 0) v
= locale
.compare(o
.locale
);
1269 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1270 if (v
== 0) v
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
);
1271 if (v
== 0) v
= screenWidthDp
.compare(o
.screenWidthDp
);
1272 if (v
== 0) v
= screenHeightDp
.compare(o
.screenHeightDp
);
1273 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1274 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1275 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1276 if (v
== 0) v
= uiModeType
.compare(o
.uiModeType
);
1277 if (v
== 0) v
= uiModeNight
.compare(o
.uiModeNight
);
1278 if (v
== 0) v
= density
.compare(o
.density
);
1279 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1280 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1281 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1282 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1283 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1284 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1285 if (v
== 0) v
= version
.compare(o
.version
);
1289 ResTable_config
AaptGroupEntry::toParams() const
1291 ResTable_config params
;
1292 memset(¶ms
, 0, sizeof(params
));
1293 getMccName(mcc
.string(), ¶ms
);
1294 getMncName(mnc
.string(), ¶ms
);
1295 getLocaleName(locale
.string(), ¶ms
);
1296 getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
);
1297 getScreenWidthDpName(screenWidthDp
.string(), ¶ms
);
1298 getScreenHeightDpName(screenHeightDp
.string(), ¶ms
);
1299 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1300 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1301 getOrientationName(orientation
.string(), ¶ms
);
1302 getUiModeTypeName(uiModeType
.string(), ¶ms
);
1303 getUiModeNightName(uiModeNight
.string(), ¶ms
);
1304 getDensityName(density
.string(), ¶ms
);
1305 getTouchscreenName(touchscreen
.string(), ¶ms
);
1306 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1307 getKeyboardName(keyboard
.string(), ¶ms
);
1308 getNavHiddenName(navHidden
.string(), ¶ms
);
1309 getNavigationName(navigation
.string(), ¶ms
);
1310 getScreenSizeName(screenSize
.string(), ¶ms
);
1311 getVersionName(version
.string(), ¶ms
);
1313 // Fix up version number based on specified parameters.
1315 if (params
.smallestScreenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1316 || params
.screenWidthDp
!= ResTable_config::SCREENWIDTH_ANY
1317 || params
.screenHeightDp
!= ResTable_config::SCREENHEIGHT_ANY
) {
1318 minSdk
= SDK_HONEYCOMB_MR2
;
1319 } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
)
1320 != ResTable_config::UI_MODE_TYPE_ANY
1321 || (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
)
1322 != ResTable_config::UI_MODE_NIGHT_ANY
) {
1324 } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
)
1325 != ResTable_config::SCREENSIZE_ANY
1326 || (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
)
1327 != ResTable_config::SCREENLONG_ANY
1328 || params
.density
!= ResTable_config::DENSITY_DEFAULT
) {
1332 if (minSdk
> params
.sdkVersion
) {
1333 params
.sdkVersion
= minSdk
;
1339 // =========================================================================
1340 // =========================================================================
1341 // =========================================================================
1343 void* AaptFile::editData(size_t size
)
1345 if (size
<= mBufferSize
) {
1349 size_t allocSize
= (size
*3)/2;
1350 void* buf
= realloc(mData
, allocSize
);
1356 mBufferSize
= allocSize
;
1360 void* AaptFile::editData(size_t* outSize
)
1363 *outSize
= mDataSize
;
1368 void* AaptFile::padData(size_t wordSize
)
1370 const size_t extra
= mDataSize%wordSize
;
1375 size_t initial
= mDataSize
;
1376 void* data
= editData(initial
+(wordSize
-extra
));
1378 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1383 status_t
AaptFile::writeData(const void* data
, size_t size
)
1385 size_t end
= mDataSize
;
1386 size_t total
= size
+ end
;
1387 void* buf
= editData(total
);
1389 return UNKNOWN_ERROR
;
1391 memcpy(((char*)buf
)+end
, data
, size
);
1395 void AaptFile::clearData()
1397 if (mData
!= NULL
) free(mData
);
1403 String8
AaptFile::getPrintableSource() const
1406 String8
name(mGroupEntry
.locale
.string());
1407 name
.appendPath(mGroupEntry
.vendor
.string());
1408 name
.appendPath(mPath
);
1409 name
.append(" #generated");
1415 // =========================================================================
1416 // =========================================================================
1417 // =========================================================================
1419 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1421 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1422 file
->mPath
= mPath
;
1423 mFiles
.add(file
->getGroupEntry(), file
);
1427 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1428 getPrintableSource().string());
1429 return UNKNOWN_ERROR
;
1432 void AaptGroup::removeFile(size_t index
)
1434 mFiles
.removeItemsAt(index
);
1437 void AaptGroup::print() const
1439 printf(" %s\n", getPath().string());
1440 const size_t N
=mFiles
.size();
1442 for (i
=0; i
<N
; i
++) {
1443 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1444 const AaptGroupEntry
& e
= file
->getGroupEntry();
1445 if (file
->hasData()) {
1446 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
1447 (int)file
->getSize());
1449 printf(" Src: %s\n", file
->getPrintableSource().string());
1454 String8
AaptGroup::getPrintableSource() const
1456 if (mFiles
.size() > 0) {
1457 // Arbitrarily pull the first source file out of the list.
1458 return mFiles
.valueAt(0)->getPrintableSource();
1461 // Should never hit this case, but to be safe...
1466 // =========================================================================
1467 // =========================================================================
1468 // =========================================================================
1470 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1472 if (mFiles
.indexOfKey(name
) >= 0) {
1473 return ALREADY_EXISTS
;
1475 mFiles
.add(name
, file
);
1479 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1481 if (mDirs
.indexOfKey(name
) >= 0) {
1482 return ALREADY_EXISTS
;
1484 mDirs
.add(name
, dir
);
1488 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1491 String8 remain
= path
;
1493 sp
<AaptDir
> subdir
= this;
1494 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1495 subdir
= subdir
->makeDir(name
);
1498 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1500 return subdir
->mDirs
.valueAt(i
);
1502 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1503 subdir
->mDirs
.add(name
, dir
);
1507 void AaptDir::removeFile(const String8
& name
)
1509 mFiles
.removeItem(name
);
1512 void AaptDir::removeDir(const String8
& name
)
1514 mDirs
.removeItem(name
);
1517 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1519 sp
<AaptGroup
> origGroup
;
1521 // Find and remove the given file with shear, brute force!
1522 const size_t NG
= mFiles
.size();
1524 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1525 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1526 const size_t NF
= g
->getFiles().size();
1527 for (size_t j
=0; j
<NF
; j
++) {
1528 if (g
->getFiles().valueAt(j
) == file
) {
1532 mFiles
.removeItemsAt(i
);
1539 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1541 // Place the file under its new name.
1542 if (origGroup
!= NULL
) {
1543 return addLeafFile(newName
, file
);
1549 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1551 sp
<AaptGroup
> group
;
1552 if (mFiles
.indexOfKey(leafName
) >= 0) {
1553 group
= mFiles
.valueFor(leafName
);
1555 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1556 mFiles
.add(leafName
, group
);
1559 return group
->addFile(file
);
1562 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1563 const AaptGroupEntry
& kind
, const String8
& resType
,
1564 sp
<FilePathStore
>& fullResPaths
)
1566 Vector
<String8
> fileNames
;
1570 dir
= opendir(srcDir
.string());
1572 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1573 return UNKNOWN_ERROR
;
1577 * Slurp the filenames out of the directory.
1580 struct dirent
* entry
;
1582 entry
= readdir(dir
);
1586 if (isHidden(srcDir
.string(), entry
->d_name
))
1589 String8
name(entry
->d_name
);
1590 fileNames
.add(name
);
1591 // Add fully qualified path for dependency purposes
1592 // if we're collecting them
1593 if (fullResPaths
!= NULL
) {
1594 fullResPaths
->add(srcDir
.appendPathCopy(name
));
1603 * Stash away the files and recursively descend into subdirectories.
1605 const size_t N
= fileNames
.size();
1607 for (i
= 0; i
< N
; i
++) {
1608 String8
pathName(srcDir
);
1611 pathName
.appendPath(fileNames
[i
].string());
1612 type
= getFileType(pathName
.string());
1613 if (type
== kFileTypeDirectory
) {
1615 bool notAdded
= false;
1616 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1617 subdir
= mDirs
.valueFor(fileNames
[i
]);
1619 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1622 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1623 resType
, fullResPaths
);
1624 if (res
< NO_ERROR
) {
1627 if (res
> 0 && notAdded
) {
1628 mDirs
.add(fileNames
[i
], subdir
);
1631 } else if (type
== kFileTypeRegular
) {
1632 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1633 status_t err
= addLeafFile(fileNames
[i
], file
);
1634 if (err
!= NO_ERROR
) {
1641 if (bundle
->getVerbose())
1642 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1649 status_t
AaptDir::validate() const
1651 const size_t NF
= mFiles
.size();
1652 const size_t ND
= mDirs
.size();
1654 for (i
= 0; i
< NF
; i
++) {
1655 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1656 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1657 "Invalid filename. Unable to add.");
1658 return UNKNOWN_ERROR
;
1662 for (j
= i
+1; j
< NF
; j
++) {
1663 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1664 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1665 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1666 "File is case-insensitive equivalent to: %s",
1667 mFiles
.valueAt(j
)->getPrintableSource().string());
1668 return UNKNOWN_ERROR
;
1671 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1672 // (this is mostly caught by the "marked" stuff, below)
1675 for (j
= 0; j
< ND
; j
++) {
1676 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1677 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1678 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1679 "File conflicts with dir from: %s",
1680 mDirs
.valueAt(j
)->getPrintableSource().string());
1681 return UNKNOWN_ERROR
;
1686 for (i
= 0; i
< ND
; i
++) {
1687 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1688 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1689 "Invalid directory name, unable to add.");
1690 return UNKNOWN_ERROR
;
1694 for (j
= i
+1; j
< ND
; j
++) {
1695 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1696 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1697 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1698 "Directory is case-insensitive equivalent to: %s",
1699 mDirs
.valueAt(j
)->getPrintableSource().string());
1700 return UNKNOWN_ERROR
;
1704 status_t err
= mDirs
.valueAt(i
)->validate();
1705 if (err
!= NO_ERROR
) {
1713 void AaptDir::print() const
1715 const size_t ND
=getDirs().size();
1717 for (i
=0; i
<ND
; i
++) {
1718 getDirs().valueAt(i
)->print();
1721 const size_t NF
=getFiles().size();
1722 for (i
=0; i
<NF
; i
++) {
1723 getFiles().valueAt(i
)->print();
1727 String8
AaptDir::getPrintableSource() const
1729 if (mFiles
.size() > 0) {
1730 // Arbitrarily pull the first file out of the list as the source dir.
1731 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1733 if (mDirs
.size() > 0) {
1734 // Or arbitrarily pull the first dir out of the list as the source dir.
1735 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1738 // Should never hit this case, but to be safe...
1743 // =========================================================================
1744 // =========================================================================
1745 // =========================================================================
1747 sp
<AaptFile
> AaptAssets::addFile(
1748 const String8
& filePath
, const AaptGroupEntry
& entry
,
1749 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1750 const String8
& resType
)
1752 sp
<AaptDir
> dir
= this;
1753 sp
<AaptGroup
> group
;
1755 String8 root
, remain(filePath
), partialPath
;
1756 while (remain
.length() > 0) {
1757 root
= remain
.walkPath(&remain
);
1758 partialPath
.appendPath(root
);
1760 const String8
rootStr(root
);
1762 if (remain
.length() == 0) {
1763 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1765 group
= dir
->getFiles().valueAt(i
);
1767 group
= new AaptGroup(rootStr
, filePath
);
1768 status_t res
= dir
->addFile(rootStr
, group
);
1769 if (res
!= NO_ERROR
) {
1773 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1774 status_t res
= group
->addFile(file
);
1775 if (res
!= NO_ERROR
) {
1781 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1783 dir
= dir
->getDirs().valueAt(i
);
1785 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1786 status_t res
= dir
->addDir(rootStr
, subdir
);
1787 if (res
!= NO_ERROR
) {
1795 mGroupEntries
.add(entry
);
1796 if (outGroup
) *outGroup
= group
;
1800 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1801 const sp
<AaptFile
>& file
, const String8
& resType
)
1803 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1804 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1805 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1806 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1809 subdir
->addFile(leafName
, grr
);
1813 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1818 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1819 const size_t dirCount
=resDirs
.size();
1820 sp
<AaptAssets
> current
= this;
1822 const int N
= bundle
->getFileSpecCount();
1825 * If a package manifest was specified, include that first.
1827 if (bundle
->getAndroidManifestFile() != NULL
) {
1828 // place at root of zip.
1829 String8
srcFile(bundle
->getAndroidManifestFile());
1830 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1836 * If a directory of custom assets was supplied, slurp 'em up.
1838 if (bundle
->getAssetSourceDir()) {
1839 const char* assetDir
= bundle
->getAssetSourceDir();
1841 FileType type
= getFileType(assetDir
);
1842 if (type
== kFileTypeNonexistent
) {
1843 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1844 return UNKNOWN_ERROR
;
1846 if (type
!= kFileTypeDirectory
) {
1847 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1848 return UNKNOWN_ERROR
;
1851 String8
assetRoot(assetDir
);
1852 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1853 AaptGroupEntry group
;
1854 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1855 String8(), mFullAssetPaths
);
1861 mGroupEntries
.add(group
);
1863 totalCount
+= count
;
1865 if (bundle
->getVerbose())
1866 printf("Found %d custom asset file%s in %s\n",
1867 count
, (count
==1) ? "" : "s", assetDir
);
1871 * If a directory of resource-specific assets was supplied, slurp 'em up.
1873 for (size_t i
=0; i
<dirCount
; i
++) {
1874 const char *res
= resDirs
[i
];
1876 type
= getFileType(res
);
1877 if (type
== kFileTypeNonexistent
) {
1878 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1879 return UNKNOWN_ERROR
;
1881 if (type
== kFileTypeDirectory
) {
1883 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1884 current
->setOverlay(nextOverlay
);
1885 current
= nextOverlay
;
1886 current
->setFullResPaths(mFullResPaths
);
1888 count
= current
->slurpResourceTree(bundle
, String8(res
));
1894 totalCount
+= count
;
1897 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1898 return UNKNOWN_ERROR
;
1904 * Now do any additional raw files.
1906 for (int arg
=0; arg
<N
; arg
++) {
1907 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1909 FileType type
= getFileType(assetDir
);
1910 if (type
== kFileTypeNonexistent
) {
1911 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1912 return UNKNOWN_ERROR
;
1914 if (type
!= kFileTypeDirectory
) {
1915 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1916 return UNKNOWN_ERROR
;
1919 String8
assetRoot(assetDir
);
1921 if (bundle
->getVerbose())
1922 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1925 * Do a recursive traversal of subdir tree. We don't make any
1926 * guarantees about ordering, so we're okay with an inorder search
1927 * using whatever order the OS happens to hand back to us.
1929 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
);
1931 /* failure; report error and remove archive */
1935 totalCount
+= count
;
1937 if (bundle
->getVerbose())
1938 printf("Found %d asset file%s in %s\n",
1939 count
, (count
==1) ? "" : "s", assetDir
);
1943 if (count
!= NO_ERROR
) {
1953 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1954 const AaptGroupEntry
& kind
,
1955 const String8
& resType
,
1956 sp
<FilePathStore
>& fullResPaths
)
1958 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
);
1960 mGroupEntries
.add(kind
);
1966 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1970 DIR* dir
= opendir(srcDir
.string());
1972 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1973 return UNKNOWN_ERROR
;
1979 * Run through the directory, looking for dirs that match the
1983 struct dirent
* entry
= readdir(dir
);
1984 if (entry
== NULL
) {
1988 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1992 String8
subdirName(srcDir
);
1993 subdirName
.appendPath(entry
->d_name
);
1995 AaptGroupEntry group
;
1997 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1999 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
2005 if (bundle
->getMaxResVersion() != NULL
&& group
.version
.length() != 0) {
2006 int maxResInt
= atoi(bundle
->getMaxResVersion());
2007 const char *verString
= group
.version
.string();
2008 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2009 if (dirVersionInt
> maxResInt
) {
2010 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2015 FileType type
= getFileType(subdirName
.string());
2017 if (type
== kFileTypeDirectory
) {
2018 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
2019 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2020 resType
, mFullResPaths
);
2026 mGroupEntries
.add(group
);
2032 if (bundle
->getVerbose()) {
2033 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2049 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2052 SortedVector
<AaptGroupEntry
> entries
;
2054 ZipFile
* zip
= new ZipFile
;
2055 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2056 if (err
!= NO_ERROR
) {
2057 fprintf(stderr
, "error opening zip file %s\n", filename
);
2063 const int N
= zip
->getNumEntries();
2064 for (int i
=0; i
<N
; i
++) {
2065 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2066 if (entry
->getDeleted()) {
2070 String8
entryName(entry
->getFileName());
2072 String8 dirName
= entryName
.getPathDir();
2073 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2076 AaptGroupEntry kind
;
2079 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2080 // these are the resources, pull their type out of the directory name
2081 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2083 // these are untyped and don't have an AaptGroupEntry
2085 if (entries
.indexOf(kind
) < 0) {
2087 mGroupEntries
.add(kind
);
2090 // use the one from the zip file if they both exist.
2091 dir
->removeFile(entryName
.getPathLeaf());
2093 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2094 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2095 if (err
!= NO_ERROR
) {
2096 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2100 file
->setCompressionMethod(entry
->getCompressionMethod());
2103 if (entryName
== "AndroidManifest.xml") {
2104 printf("AndroidManifest.xml\n");
2106 printf("\n\nfile: %s\n", entryName
.string());
2109 size_t len
= entry
->getUncompressedLen();
2110 void* data
= zip
->uncompress(entry
);
2111 void* buf
= file
->editData(len
);
2112 memcpy(buf
, data
, len
);
2116 const unsigned char* p
= (unsigned char*)data
;
2117 const unsigned char* end
= p
+len
;
2119 for (int i
=0; i
<32 && p
< end
; i
++) {
2120 printf("0x%03x ", i
*0x10 + OFF
);
2121 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2122 printf(" %02x", *p
);
2139 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2141 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2143 sym
= new AaptSymbols();
2144 mSymbols
.add(name
, sym
);
2149 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2151 if (!mHaveIncludedAssets
) {
2152 // Add in all includes.
2153 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2154 const size_t N
=incl
.size();
2155 for (size_t i
=0; i
<N
; i
++) {
2156 if (bundle
->getVerbose())
2157 printf("Including resources from package: %s\n", incl
[i
]);
2158 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2159 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2161 return UNKNOWN_ERROR
;
2164 mHaveIncludedAssets
= true;
2170 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2172 const ResTable
& res
= getIncludedResources();
2174 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2177 const ResTable
& AaptAssets::getIncludedResources() const
2179 return mIncludedAssets
.getResources(false);
2182 void AaptAssets::print() const
2184 printf("Locale/Vendor pairs:\n");
2185 const size_t N
=mGroupEntries
.size();
2186 for (size_t i
=0; i
<N
; i
++) {
2188 mGroupEntries
.itemAt(i
).locale
.string(),
2189 mGroupEntries
.itemAt(i
).vendor
.string());
2192 printf("\nFiles:\n");
2196 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
)
2198 const Vector
<sp
<AaptDir
> >& dirs
= mDirs
;
2199 const size_t N
= dirs
.size();
2200 for (size_t i
=0; i
<N
; i
++) {
2201 const sp
<AaptDir
>& d
= dirs
.itemAt(i
);
2202 if (d
->getLeaf() == name
) {
2210 valid_symbol_name(const String8
& symbol
)
2212 static char const * const KEYWORDS
[] = {
2213 "abstract", "assert", "boolean", "break",
2214 "byte", "case", "catch", "char", "class", "const", "continue",
2215 "default", "do", "double", "else", "enum", "extends", "final",
2216 "finally", "float", "for", "goto", "if", "implements", "import",
2217 "instanceof", "int", "interface", "long", "native", "new", "package",
2218 "private", "protected", "public", "return", "short", "static",
2219 "strictfp", "super", "switch", "synchronized", "this", "throw",
2220 "throws", "transient", "try", "void", "volatile", "while",
2221 "true", "false", "null",
2224 const char*const* k
= KEYWORDS
;
2225 const char*const s
= symbol
.string();
2227 if (0 == strcmp(s
, *k
)) {