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
)
1565 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 fileNames
.add(String8(entry
->d_name
));
1598 * Stash away the files and recursively descend into subdirectories.
1600 const size_t N
= fileNames
.size();
1602 for (i
= 0; i
< N
; i
++) {
1603 String8
pathName(srcDir
);
1606 pathName
.appendPath(fileNames
[i
].string());
1607 type
= getFileType(pathName
.string());
1608 if (type
== kFileTypeDirectory
) {
1610 bool notAdded
= false;
1611 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1612 subdir
= mDirs
.valueFor(fileNames
[i
]);
1614 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1617 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1619 if (res
< NO_ERROR
) {
1622 if (res
> 0 && notAdded
) {
1623 mDirs
.add(fileNames
[i
], subdir
);
1626 } else if (type
== kFileTypeRegular
) {
1627 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1628 status_t err
= addLeafFile(fileNames
[i
], file
);
1629 if (err
!= NO_ERROR
) {
1636 if (bundle
->getVerbose())
1637 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1644 status_t
AaptDir::validate() const
1646 const size_t NF
= mFiles
.size();
1647 const size_t ND
= mDirs
.size();
1649 for (i
= 0; i
< NF
; i
++) {
1650 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1651 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1652 "Invalid filename. Unable to add.");
1653 return UNKNOWN_ERROR
;
1657 for (j
= i
+1; j
< NF
; j
++) {
1658 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1659 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1660 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1661 "File is case-insensitive equivalent to: %s",
1662 mFiles
.valueAt(j
)->getPrintableSource().string());
1663 return UNKNOWN_ERROR
;
1666 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1667 // (this is mostly caught by the "marked" stuff, below)
1670 for (j
= 0; j
< ND
; j
++) {
1671 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1672 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1673 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1674 "File conflicts with dir from: %s",
1675 mDirs
.valueAt(j
)->getPrintableSource().string());
1676 return UNKNOWN_ERROR
;
1681 for (i
= 0; i
< ND
; i
++) {
1682 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1683 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1684 "Invalid directory name, unable to add.");
1685 return UNKNOWN_ERROR
;
1689 for (j
= i
+1; j
< ND
; j
++) {
1690 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1691 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1692 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1693 "Directory is case-insensitive equivalent to: %s",
1694 mDirs
.valueAt(j
)->getPrintableSource().string());
1695 return UNKNOWN_ERROR
;
1699 status_t err
= mDirs
.valueAt(i
)->validate();
1700 if (err
!= NO_ERROR
) {
1708 void AaptDir::print() const
1710 const size_t ND
=getDirs().size();
1712 for (i
=0; i
<ND
; i
++) {
1713 getDirs().valueAt(i
)->print();
1716 const size_t NF
=getFiles().size();
1717 for (i
=0; i
<NF
; i
++) {
1718 getFiles().valueAt(i
)->print();
1722 String8
AaptDir::getPrintableSource() const
1724 if (mFiles
.size() > 0) {
1725 // Arbitrarily pull the first file out of the list as the source dir.
1726 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1728 if (mDirs
.size() > 0) {
1729 // Or arbitrarily pull the first dir out of the list as the source dir.
1730 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1733 // Should never hit this case, but to be safe...
1738 // =========================================================================
1739 // =========================================================================
1740 // =========================================================================
1742 sp
<AaptFile
> AaptAssets::addFile(
1743 const String8
& filePath
, const AaptGroupEntry
& entry
,
1744 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1745 const String8
& resType
)
1747 sp
<AaptDir
> dir
= this;
1748 sp
<AaptGroup
> group
;
1750 String8 root
, remain(filePath
), partialPath
;
1751 while (remain
.length() > 0) {
1752 root
= remain
.walkPath(&remain
);
1753 partialPath
.appendPath(root
);
1755 const String8
rootStr(root
);
1757 if (remain
.length() == 0) {
1758 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1760 group
= dir
->getFiles().valueAt(i
);
1762 group
= new AaptGroup(rootStr
, filePath
);
1763 status_t res
= dir
->addFile(rootStr
, group
);
1764 if (res
!= NO_ERROR
) {
1768 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1769 status_t res
= group
->addFile(file
);
1770 if (res
!= NO_ERROR
) {
1776 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1778 dir
= dir
->getDirs().valueAt(i
);
1780 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1781 status_t res
= dir
->addDir(rootStr
, subdir
);
1782 if (res
!= NO_ERROR
) {
1790 mGroupEntries
.add(entry
);
1791 if (outGroup
) *outGroup
= group
;
1795 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1796 const sp
<AaptFile
>& file
, const String8
& resType
)
1798 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1799 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1800 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1801 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1804 subdir
->addFile(leafName
, grr
);
1808 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1813 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1814 const size_t dirCount
=resDirs
.size();
1815 sp
<AaptAssets
> current
= this;
1817 const int N
= bundle
->getFileSpecCount();
1820 * If a package manifest was specified, include that first.
1822 if (bundle
->getAndroidManifestFile() != NULL
) {
1823 // place at root of zip.
1824 String8
srcFile(bundle
->getAndroidManifestFile());
1825 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1831 * If a directory of custom assets was supplied, slurp 'em up.
1833 if (bundle
->getAssetSourceDir()) {
1834 const char* assetDir
= bundle
->getAssetSourceDir();
1836 FileType type
= getFileType(assetDir
);
1837 if (type
== kFileTypeNonexistent
) {
1838 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1839 return UNKNOWN_ERROR
;
1841 if (type
!= kFileTypeDirectory
) {
1842 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1843 return UNKNOWN_ERROR
;
1846 String8
assetRoot(assetDir
);
1847 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1848 AaptGroupEntry group
;
1849 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1856 mGroupEntries
.add(group
);
1858 totalCount
+= count
;
1860 if (bundle
->getVerbose())
1861 printf("Found %d custom asset file%s in %s\n",
1862 count
, (count
==1) ? "" : "s", assetDir
);
1866 * If a directory of resource-specific assets was supplied, slurp 'em up.
1868 for (size_t i
=0; i
<dirCount
; i
++) {
1869 const char *res
= resDirs
[i
];
1871 type
= getFileType(res
);
1872 if (type
== kFileTypeNonexistent
) {
1873 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1874 return UNKNOWN_ERROR
;
1876 if (type
== kFileTypeDirectory
) {
1878 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1879 current
->setOverlay(nextOverlay
);
1880 current
= nextOverlay
;
1882 count
= current
->slurpResourceTree(bundle
, String8(res
));
1888 totalCount
+= count
;
1891 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1892 return UNKNOWN_ERROR
;
1898 * Now do any additional raw files.
1900 for (int arg
=0; arg
<N
; arg
++) {
1901 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1903 FileType type
= getFileType(assetDir
);
1904 if (type
== kFileTypeNonexistent
) {
1905 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1906 return UNKNOWN_ERROR
;
1908 if (type
!= kFileTypeDirectory
) {
1909 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1910 return UNKNOWN_ERROR
;
1913 String8
assetRoot(assetDir
);
1915 if (bundle
->getVerbose())
1916 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1919 * Do a recursive traversal of subdir tree. We don't make any
1920 * guarantees about ordering, so we're okay with an inorder search
1921 * using whatever order the OS happens to hand back to us.
1923 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1925 /* failure; report error and remove archive */
1929 totalCount
+= count
;
1931 if (bundle
->getVerbose())
1932 printf("Found %d asset file%s in %s\n",
1933 count
, (count
==1) ? "" : "s", assetDir
);
1937 if (count
!= NO_ERROR
) {
1947 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1948 const AaptGroupEntry
& kind
,
1949 const String8
& resType
)
1951 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1953 mGroupEntries
.add(kind
);
1959 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1963 DIR* dir
= opendir(srcDir
.string());
1965 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1966 return UNKNOWN_ERROR
;
1972 * Run through the directory, looking for dirs that match the
1976 struct dirent
* entry
= readdir(dir
);
1977 if (entry
== NULL
) {
1981 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1985 String8
subdirName(srcDir
);
1986 subdirName
.appendPath(entry
->d_name
);
1988 AaptGroupEntry group
;
1990 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1992 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1998 if (bundle
->getMaxResVersion() != NULL
&& group
.version
.length() != 0) {
1999 int maxResInt
= atoi(bundle
->getMaxResVersion());
2000 const char *verString
= group
.version
.string();
2001 int dirVersionInt
= atoi(verString
+ 1); // skip 'v' in version name
2002 if (dirVersionInt
> maxResInt
) {
2003 fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
);
2008 FileType type
= getFileType(subdirName
.string());
2010 if (type
== kFileTypeDirectory
) {
2011 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
2012 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
2019 mGroupEntries
.add(group
);
2025 if (bundle
->getVerbose()) {
2026 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
2042 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
2045 SortedVector
<AaptGroupEntry
> entries
;
2047 ZipFile
* zip
= new ZipFile
;
2048 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
2049 if (err
!= NO_ERROR
) {
2050 fprintf(stderr
, "error opening zip file %s\n", filename
);
2056 const int N
= zip
->getNumEntries();
2057 for (int i
=0; i
<N
; i
++) {
2058 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
2059 if (entry
->getDeleted()) {
2063 String8
entryName(entry
->getFileName());
2065 String8 dirName
= entryName
.getPathDir();
2066 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
2069 AaptGroupEntry kind
;
2072 if (entryName
.walkPath(&remain
) == kResourceDir
) {
2073 // these are the resources, pull their type out of the directory name
2074 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
2076 // these are untyped and don't have an AaptGroupEntry
2078 if (entries
.indexOf(kind
) < 0) {
2080 mGroupEntries
.add(kind
);
2083 // use the one from the zip file if they both exist.
2084 dir
->removeFile(entryName
.getPathLeaf());
2086 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
2087 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
2088 if (err
!= NO_ERROR
) {
2089 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
2093 file
->setCompressionMethod(entry
->getCompressionMethod());
2096 if (entryName
== "AndroidManifest.xml") {
2097 printf("AndroidManifest.xml\n");
2099 printf("\n\nfile: %s\n", entryName
.string());
2102 size_t len
= entry
->getUncompressedLen();
2103 void* data
= zip
->uncompress(entry
);
2104 void* buf
= file
->editData(len
);
2105 memcpy(buf
, data
, len
);
2109 const unsigned char* p
= (unsigned char*)data
;
2110 const unsigned char* end
= p
+len
;
2112 for (int i
=0; i
<32 && p
< end
; i
++) {
2113 printf("0x%03x ", i
*0x10 + OFF
);
2114 for (int j
=0; j
<0x10 && p
< end
; j
++) {
2115 printf(" %02x", *p
);
2132 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
2134 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
2136 sym
= new AaptSymbols();
2137 mSymbols
.add(name
, sym
);
2142 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
2144 if (!mHaveIncludedAssets
) {
2145 // Add in all includes.
2146 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
2147 const size_t N
=incl
.size();
2148 for (size_t i
=0; i
<N
; i
++) {
2149 if (bundle
->getVerbose())
2150 printf("Including resources from package: %s\n", incl
[i
]);
2151 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
2152 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
2154 return UNKNOWN_ERROR
;
2157 mHaveIncludedAssets
= true;
2163 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
2165 const ResTable
& res
= getIncludedResources();
2167 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
2170 const ResTable
& AaptAssets::getIncludedResources() const
2172 return mIncludedAssets
.getResources(false);
2175 void AaptAssets::print() const
2177 printf("Locale/Vendor pairs:\n");
2178 const size_t N
=mGroupEntries
.size();
2179 for (size_t i
=0; i
<N
; i
++) {
2181 mGroupEntries
.itemAt(i
).locale
.string(),
2182 mGroupEntries
.itemAt(i
).vendor
.string());
2185 printf("\nFiles:\n");
2189 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
)
2191 const Vector
<sp
<AaptDir
> >& dirs
= mDirs
;
2192 const size_t N
= dirs
.size();
2193 for (size_t i
=0; i
<N
; i
++) {
2194 const sp
<AaptDir
>& d
= dirs
.itemAt(i
);
2195 if (d
->getLeaf() == name
) {
2203 valid_symbol_name(const String8
& symbol
)
2205 static char const * const KEYWORDS
[] = {
2206 "abstract", "assert", "boolean", "break",
2207 "byte", "case", "catch", "char", "class", "const", "continue",
2208 "default", "do", "double", "else", "enum", "extends", "final",
2209 "finally", "float", "for", "goto", "if", "implements", "import",
2210 "instanceof", "int", "interface", "long", "native", "new", "package",
2211 "private", "protected", "public", "return", "short", "static",
2212 "strictfp", "super", "switch", "synchronized", "this", "throw",
2213 "throws", "transient", "try", "void", "volatile", "while",
2214 "true", "false", "null",
2217 const char*const* k
= KEYWORDS
;
2218 const char*const s
= symbol
.string();
2220 if (0 == strcmp(s
, *k
)) {