]>
git.saurik.com Git - android/aapt.git/blob - AaptAssets.cpp
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 // screen layout size
146 if (getScreenLayoutSizeName(part
.string(), &config
)) {
147 *axis
= AXIS_SCREENLAYOUTSIZE
;
148 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
152 // screen layout long
153 if (getScreenLayoutLongName(part
.string(), &config
)) {
154 *axis
= AXIS_SCREENLAYOUTLONG
;
155 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
160 if (getOrientationName(part
.string(), &config
)) {
161 *axis
= AXIS_ORIENTATION
;
162 *value
= config
.orientation
;
167 if (getDensityName(part
.string(), &config
)) {
168 *axis
= AXIS_DENSITY
;
169 *value
= config
.density
;
174 if (getTouchscreenName(part
.string(), &config
)) {
175 *axis
= AXIS_TOUCHSCREEN
;
176 *value
= config
.touchscreen
;
181 if (getKeysHiddenName(part
.string(), &config
)) {
182 *axis
= AXIS_KEYSHIDDEN
;
183 *value
= config
.inputFlags
;
188 if (getKeyboardName(part
.string(), &config
)) {
189 *axis
= AXIS_KEYBOARD
;
190 *value
= config
.keyboard
;
195 if (getNavHiddenName(part
.string(), &config
)) {
196 *axis
= AXIS_NAVHIDDEN
;
197 *value
= config
.inputFlags
;
202 if (getNavigationName(part
.string(), &config
)) {
203 *axis
= AXIS_NAVIGATION
;
204 *value
= config
.navigation
;
209 if (getScreenSizeName(part
.string(), &config
)) {
210 *axis
= AXIS_SCREENSIZE
;
211 *value
= config
.screenSize
;
216 if (getVersionName(part
.string(), &config
)) {
217 *axis
= AXIS_VERSION
;
218 *value
= config
.version
;
226 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
228 Vector
<String8
> parts
;
230 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
231 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
;
235 while (NULL
!= (q
= strchr(p
, '-'))) {
239 //printf("part: %s\n", parts[parts.size()-1].string());
245 //printf("part: %s\n", parts[parts.size()-1].string());
247 const int N
= parts
.size();
249 String8 part
= parts
[index
];
252 if (!isValidResourceType(part
)) {
264 if (getMccName(part
.string())) {
273 //printf("not mcc: %s\n", part.string());
277 if (getMncName(part
.string())) {
286 //printf("not mcc: %s\n", part.string());
290 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
299 //printf("not language: %s\n", part.string());
304 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
307 loc
+= part
.string() + 1;
315 //printf("not region: %s\n", part.string());
318 if (getScreenLayoutSizeName(part
.string())) {
327 //printf("not screen layout size: %s\n", part.string());
330 if (getScreenLayoutLongName(part
.string())) {
339 //printf("not screen layout long: %s\n", part.string());
343 if (getOrientationName(part
.string())) {
352 //printf("not orientation: %s\n", part.string());
356 if (getDensityName(part
.string())) {
365 //printf("not density: %s\n", part.string());
369 if (getTouchscreenName(part
.string())) {
378 //printf("not touchscreen: %s\n", part.string());
382 if (getKeysHiddenName(part
.string())) {
391 //printf("not keysHidden: %s\n", part.string());
395 if (getKeyboardName(part
.string())) {
404 //printf("not keyboard: %s\n", part.string());
408 if (getNavHiddenName(part
.string())) {
417 //printf("not navHidden: %s\n", part.string());
420 if (getNavigationName(part
.string())) {
429 //printf("not navigation: %s\n", part.string());
432 if (getScreenSizeName(part
.string())) {
441 //printf("not screen size: %s\n", part.string());
444 if (getVersionName(part
.string())) {
453 //printf("not version: %s\n", part.string());
456 // if there are extra parts, it doesn't match
463 this->screenLayoutSize
= layoutsize
;
464 this->screenLayoutLong
= layoutlong
;
465 this->orientation
= orient
;
467 this->touchscreen
= touch
;
468 this->keysHidden
= keysHidden
;
469 this->keyboard
= key
;
470 this->navHidden
= navHidden
;
471 this->navigation
= nav
;
472 this->screenSize
= size
;
473 this->version
= vers
;
475 // what is this anyway?
482 AaptGroupEntry::toString() const
484 String8 s
= this->mcc
;
490 s
+= screenLayoutSize
;
492 s
+= screenLayoutLong
;
494 s
+= this->orientation
;
515 AaptGroupEntry::toDirName(const String8
& resType
) const
518 if (this->mcc
!= "") {
522 if (this->mnc
!= "") {
526 if (this->locale
!= "") {
530 if (this->screenLayoutSize
!= "") {
532 s
+= screenLayoutSize
;
534 if (this->screenLayoutLong
!= "") {
536 s
+= screenLayoutLong
;
538 if (this->orientation
!= "") {
542 if (this->density
!= "") {
546 if (this->touchscreen
!= "") {
550 if (this->keysHidden
!= "") {
554 if (this->keyboard
!= "") {
558 if (this->navHidden
!= "") {
562 if (this->navigation
!= "") {
566 if (this->screenSize
!= "") {
570 if (this->version
!= "") {
578 bool AaptGroupEntry::getMccName(const char* name
,
579 ResTable_config
* out
)
581 if (strcmp(name
, kWildcardName
) == 0) {
582 if (out
) out
->mcc
= 0;
585 const char* c
= name
;
586 if (tolower(*c
) != 'm') return false;
588 if (tolower(*c
) != 'c') return false;
590 if (tolower(*c
) != 'c') return false;
595 while (*c
>= '0' && *c
<= '9') {
598 if (*c
!= 0) return false;
599 if (c
-val
!= 3) return false;
603 if (out
) out
->mcc
= d
;
610 bool AaptGroupEntry::getMncName(const char* name
,
611 ResTable_config
* out
)
613 if (strcmp(name
, kWildcardName
) == 0) {
614 if (out
) out
->mcc
= 0;
617 const char* c
= name
;
618 if (tolower(*c
) != 'm') return false;
620 if (tolower(*c
) != 'n') return false;
622 if (tolower(*c
) != 'c') return false;
627 while (*c
>= '0' && *c
<= '9') {
630 if (*c
!= 0) return false;
631 if (c
-val
== 0 || c
-val
> 3) return false;
635 if (out
) out
->mnc
= d
;
643 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
646 * TODO: Should insist that the first two letters are lower case, and the
647 * second two are upper.
649 bool AaptGroupEntry::getLocaleName(const char* fileName
,
650 ResTable_config
* out
)
652 if (strcmp(fileName
, kWildcardName
) == 0
653 || strcmp(fileName
, kDefaultLocale
) == 0) {
655 out
->language
[0] = 0;
656 out
->language
[1] = 0;
663 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
665 out
->language
[0] = fileName
[0];
666 out
->language
[1] = fileName
[1];
673 if (strlen(fileName
) == 5 &&
674 isalpha(fileName
[0]) &&
675 isalpha(fileName
[1]) &&
676 fileName
[2] == '-' &&
677 isalpha(fileName
[3]) &&
678 isalpha(fileName
[4])) {
680 out
->language
[0] = fileName
[0];
681 out
->language
[1] = fileName
[1];
682 out
->country
[0] = fileName
[3];
683 out
->country
[1] = fileName
[4];
691 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
692 ResTable_config
* out
)
694 if (strcmp(name
, kWildcardName
) == 0) {
695 if (out
) out
->screenLayout
=
696 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
697 | ResTable_config::SCREENSIZE_ANY
;
699 } else if (strcmp(name
, "small") == 0) {
700 if (out
) out
->screenLayout
=
701 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
702 | ResTable_config::SCREENSIZE_SMALL
;
704 } else if (strcmp(name
, "normal") == 0) {
705 if (out
) out
->screenLayout
=
706 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
707 | ResTable_config::SCREENSIZE_NORMAL
;
709 } else if (strcmp(name
, "large") == 0) {
710 if (out
) out
->screenLayout
=
711 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
712 | ResTable_config::SCREENSIZE_LARGE
;
719 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
720 ResTable_config
* out
)
722 if (strcmp(name
, kWildcardName
) == 0) {
723 if (out
) out
->screenLayout
=
724 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
725 | ResTable_config::SCREENLONG_ANY
;
727 } else if (strcmp(name
, "long") == 0) {
728 if (out
) out
->screenLayout
=
729 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
730 | ResTable_config::SCREENLONG_YES
;
732 } else if (strcmp(name
, "notlong") == 0) {
733 if (out
) out
->screenLayout
=
734 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
735 | ResTable_config::SCREENLONG_NO
;
742 bool AaptGroupEntry::getOrientationName(const char* name
,
743 ResTable_config
* out
)
745 if (strcmp(name
, kWildcardName
) == 0) {
746 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
748 } else if (strcmp(name
, "port") == 0) {
749 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
751 } else if (strcmp(name
, "land") == 0) {
752 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
754 } else if (strcmp(name
, "square") == 0) {
755 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
762 bool AaptGroupEntry::getDensityName(const char* name
,
763 ResTable_config
* out
)
765 if (strcmp(name
, kWildcardName
) == 0) {
766 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
770 if (strcmp(name
, "nodpi") == 0) {
771 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
775 if (strcmp(name
, "ldpi") == 0) {
776 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
780 if (strcmp(name
, "mdpi") == 0) {
781 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
785 if (strcmp(name
, "hdpi") == 0) {
786 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
790 char* c
= (char*)name
;
791 while (*c
>= '0' && *c
<= '9') {
795 // check that we have 'dpi' after the last digit.
796 if (toupper(c
[0]) != 'D' ||
797 toupper(c
[1]) != 'P' ||
798 toupper(c
[2]) != 'I' ||
803 // temporarily replace the first letter with \0 to
812 if (out
) out
->density
= d
;
819 bool AaptGroupEntry::getTouchscreenName(const char* name
,
820 ResTable_config
* out
)
822 if (strcmp(name
, kWildcardName
) == 0) {
823 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
825 } else if (strcmp(name
, "notouch") == 0) {
826 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
828 } else if (strcmp(name
, "stylus") == 0) {
829 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
831 } else if (strcmp(name
, "finger") == 0) {
832 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
839 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
840 ResTable_config
* out
)
844 if (strcmp(name
, kWildcardName
) == 0) {
845 mask
= out
->MASK_KEYSHIDDEN
;
846 value
= out
->KEYSHIDDEN_ANY
;
847 } else if (strcmp(name
, "keysexposed") == 0) {
848 mask
= out
->MASK_KEYSHIDDEN
;
849 value
= out
->KEYSHIDDEN_NO
;
850 } else if (strcmp(name
, "keyshidden") == 0) {
851 mask
= out
->MASK_KEYSHIDDEN
;
852 value
= out
->KEYSHIDDEN_YES
;
853 } else if (strcmp(name
, "keyssoft") == 0) {
854 mask
= out
->MASK_KEYSHIDDEN
;
855 value
= out
->KEYSHIDDEN_SOFT
;
859 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
866 bool AaptGroupEntry::getKeyboardName(const char* name
,
867 ResTable_config
* out
)
869 if (strcmp(name
, kWildcardName
) == 0) {
870 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
872 } else if (strcmp(name
, "nokeys") == 0) {
873 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
875 } else if (strcmp(name
, "qwerty") == 0) {
876 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
878 } else if (strcmp(name
, "12key") == 0) {
879 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
886 bool AaptGroupEntry::getNavHiddenName(const char* name
,
887 ResTable_config
* out
)
891 if (strcmp(name
, kWildcardName
) == 0) {
892 mask
= out
->MASK_NAVHIDDEN
;
893 value
= out
->NAVHIDDEN_ANY
;
894 } else if (strcmp(name
, "navexposed") == 0) {
895 mask
= out
->MASK_NAVHIDDEN
;
896 value
= out
->NAVHIDDEN_NO
;
897 } else if (strcmp(name
, "navhidden") == 0) {
898 mask
= out
->MASK_NAVHIDDEN
;
899 value
= out
->NAVHIDDEN_YES
;
903 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
910 bool AaptGroupEntry::getNavigationName(const char* name
,
911 ResTable_config
* out
)
913 if (strcmp(name
, kWildcardName
) == 0) {
914 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
916 } else if (strcmp(name
, "nonav") == 0) {
917 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
919 } else if (strcmp(name
, "dpad") == 0) {
920 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
922 } else if (strcmp(name
, "trackball") == 0) {
923 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
925 } else if (strcmp(name
, "wheel") == 0) {
926 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
933 bool AaptGroupEntry::getScreenSizeName(const char* name
,
934 ResTable_config
* out
)
936 if (strcmp(name
, kWildcardName
) == 0) {
938 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
939 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
944 const char* x
= name
;
945 while (*x
>= '0' && *x
<= '9') x
++;
946 if (x
== name
|| *x
!= 'x') return false;
947 String8
xName(name
, x
-name
);
951 while (*y
>= '0' && *y
<= '9') y
++;
952 if (y
== name
|| *y
!= 0) return false;
953 String8
yName(x
, y
-x
);
955 uint16_t w
= (uint16_t)atoi(xName
.string());
956 uint16_t h
= (uint16_t)atoi(yName
.string());
962 out
->screenWidth
= w
;
963 out
->screenHeight
= h
;
969 bool AaptGroupEntry::getVersionName(const char* name
,
970 ResTable_config
* out
)
972 if (strcmp(name
, kWildcardName
) == 0) {
974 out
->sdkVersion
= out
->SDKVERSION_ANY
;
975 out
->minorVersion
= out
->MINORVERSION_ANY
;
985 const char* s
= name
;
986 while (*s
>= '0' && *s
<= '9') s
++;
987 if (s
== name
|| *s
!= 0) return false;
988 String8
sdkName(name
, s
-name
);
991 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
992 out
->minorVersion
= 0;
998 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
1000 int v
= mcc
.compare(o
.mcc
);
1001 if (v
== 0) v
= mnc
.compare(o
.mnc
);
1002 if (v
== 0) v
= locale
.compare(o
.locale
);
1003 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1004 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1005 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1006 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1007 if (v
== 0) v
= density
.compare(o
.density
);
1008 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1009 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1010 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1011 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1012 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1013 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1014 if (v
== 0) v
= version
.compare(o
.version
);
1018 ResTable_config
AaptGroupEntry::toParams() const
1020 ResTable_config params
;
1021 memset(¶ms
, 0, sizeof(params
));
1022 getMccName(mcc
.string(), ¶ms
);
1023 getMncName(mnc
.string(), ¶ms
);
1024 getLocaleName(locale
.string(), ¶ms
);
1025 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1026 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1027 getOrientationName(orientation
.string(), ¶ms
);
1028 getDensityName(density
.string(), ¶ms
);
1029 getTouchscreenName(touchscreen
.string(), ¶ms
);
1030 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1031 getKeyboardName(keyboard
.string(), ¶ms
);
1032 getNavHiddenName(navHidden
.string(), ¶ms
);
1033 getNavigationName(navigation
.string(), ¶ms
);
1034 getScreenSizeName(screenSize
.string(), ¶ms
);
1035 getVersionName(version
.string(), ¶ms
);
1039 // =========================================================================
1040 // =========================================================================
1041 // =========================================================================
1043 void* AaptFile::editData(size_t size
)
1045 if (size
<= mBufferSize
) {
1049 size_t allocSize
= (size
*3)/2;
1050 void* buf
= realloc(mData
, allocSize
);
1056 mBufferSize
= allocSize
;
1060 void* AaptFile::editData(size_t* outSize
)
1063 *outSize
= mDataSize
;
1068 void* AaptFile::padData(size_t wordSize
)
1070 const size_t extra
= mDataSize%wordSize
;
1075 size_t initial
= mDataSize
;
1076 void* data
= editData(initial
+(wordSize
-extra
));
1078 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1083 status_t
AaptFile::writeData(const void* data
, size_t size
)
1085 size_t end
= mDataSize
;
1086 size_t total
= size
+ end
;
1087 void* buf
= editData(total
);
1089 return UNKNOWN_ERROR
;
1091 memcpy(((char*)buf
)+end
, data
, size
);
1095 void AaptFile::clearData()
1097 if (mData
!= NULL
) free(mData
);
1103 String8
AaptFile::getPrintableSource() const
1106 String8
name(mGroupEntry
.locale
.string());
1107 name
.appendPath(mGroupEntry
.vendor
.string());
1108 name
.appendPath(mPath
);
1109 name
.append(" #generated");
1115 // =========================================================================
1116 // =========================================================================
1117 // =========================================================================
1119 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1121 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1122 file
->mPath
= mPath
;
1123 mFiles
.add(file
->getGroupEntry(), file
);
1127 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1128 getPrintableSource().string());
1129 return UNKNOWN_ERROR
;
1132 void AaptGroup::removeFile(size_t index
)
1134 mFiles
.removeItemsAt(index
);
1137 void AaptGroup::print() const
1139 printf(" %s\n", getPath().string());
1140 const size_t N
=mFiles
.size();
1142 for (i
=0; i
<N
; i
++) {
1143 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1144 const AaptGroupEntry
& e
= file
->getGroupEntry();
1145 if (file
->hasData()) {
1146 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
1147 (int)file
->getSize());
1149 printf(" Src: %s\n", file
->getPrintableSource().string());
1154 String8
AaptGroup::getPrintableSource() const
1156 if (mFiles
.size() > 0) {
1157 // Arbitrarily pull the first source file out of the list.
1158 return mFiles
.valueAt(0)->getPrintableSource();
1161 // Should never hit this case, but to be safe...
1166 // =========================================================================
1167 // =========================================================================
1168 // =========================================================================
1170 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1172 if (mFiles
.indexOfKey(name
) >= 0) {
1173 return ALREADY_EXISTS
;
1175 mFiles
.add(name
, file
);
1179 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1181 if (mDirs
.indexOfKey(name
) >= 0) {
1182 return ALREADY_EXISTS
;
1184 mDirs
.add(name
, dir
);
1188 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1191 String8 remain
= path
;
1193 sp
<AaptDir
> subdir
= this;
1194 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1195 subdir
= subdir
->makeDir(name
);
1198 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1200 return subdir
->mDirs
.valueAt(i
);
1202 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1203 subdir
->mDirs
.add(name
, dir
);
1207 void AaptDir::removeFile(const String8
& name
)
1209 mFiles
.removeItem(name
);
1212 void AaptDir::removeDir(const String8
& name
)
1214 mDirs
.removeItem(name
);
1217 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1219 sp
<AaptGroup
> origGroup
;
1221 // Find and remove the given file with shear, brute force!
1222 const size_t NG
= mFiles
.size();
1224 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1225 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1226 const size_t NF
= g
->getFiles().size();
1227 for (size_t j
=0; j
<NF
; j
++) {
1228 if (g
->getFiles().valueAt(j
) == file
) {
1232 mFiles
.removeItemsAt(i
);
1239 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1241 // Place the file under its new name.
1242 if (origGroup
!= NULL
) {
1243 return addLeafFile(newName
, file
);
1249 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1251 sp
<AaptGroup
> group
;
1252 if (mFiles
.indexOfKey(leafName
) >= 0) {
1253 group
= mFiles
.valueFor(leafName
);
1255 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1256 mFiles
.add(leafName
, group
);
1259 return group
->addFile(file
);
1262 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1263 const AaptGroupEntry
& kind
, const String8
& resType
)
1265 Vector
<String8
> fileNames
;
1270 dir
= opendir(srcDir
.string());
1272 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1273 return UNKNOWN_ERROR
;
1277 * Slurp the filenames out of the directory.
1280 struct dirent
* entry
;
1282 entry
= readdir(dir
);
1286 if (isHidden(srcDir
.string(), entry
->d_name
))
1289 fileNames
.add(String8(entry
->d_name
));
1298 * Stash away the files and recursively descend into subdirectories.
1300 const size_t N
= fileNames
.size();
1302 for (i
= 0; i
< N
; i
++) {
1303 String8
pathName(srcDir
);
1306 pathName
.appendPath(fileNames
[i
].string());
1307 type
= getFileType(pathName
.string());
1308 if (type
== kFileTypeDirectory
) {
1310 bool notAdded
= false;
1311 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1312 subdir
= mDirs
.valueFor(fileNames
[i
]);
1314 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1317 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1319 if (res
< NO_ERROR
) {
1322 if (res
> 0 && notAdded
) {
1323 mDirs
.add(fileNames
[i
], subdir
);
1326 } else if (type
== kFileTypeRegular
) {
1327 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1328 status_t err
= addLeafFile(fileNames
[i
], file
);
1329 if (err
!= NO_ERROR
) {
1336 if (bundle
->getVerbose())
1337 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1344 status_t
AaptDir::validate() const
1346 const size_t NF
= mFiles
.size();
1347 const size_t ND
= mDirs
.size();
1349 for (i
= 0; i
< NF
; i
++) {
1350 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1351 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1352 "Invalid filename. Unable to add.");
1353 return UNKNOWN_ERROR
;
1357 for (j
= i
+1; j
< NF
; j
++) {
1358 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1359 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1360 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1361 "File is case-insensitive equivalent to: %s",
1362 mFiles
.valueAt(j
)->getPrintableSource().string());
1363 return UNKNOWN_ERROR
;
1366 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1367 // (this is mostly caught by the "marked" stuff, below)
1370 for (j
= 0; j
< ND
; j
++) {
1371 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1372 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1373 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1374 "File conflicts with dir from: %s",
1375 mDirs
.valueAt(j
)->getPrintableSource().string());
1376 return UNKNOWN_ERROR
;
1381 for (i
= 0; i
< ND
; i
++) {
1382 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1383 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1384 "Invalid directory name, unable to add.");
1385 return UNKNOWN_ERROR
;
1389 for (j
= i
+1; j
< ND
; j
++) {
1390 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1391 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1392 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1393 "Directory is case-insensitive equivalent to: %s",
1394 mDirs
.valueAt(j
)->getPrintableSource().string());
1395 return UNKNOWN_ERROR
;
1399 status_t err
= mDirs
.valueAt(i
)->validate();
1400 if (err
!= NO_ERROR
) {
1408 void AaptDir::print() const
1410 const size_t ND
=getDirs().size();
1412 for (i
=0; i
<ND
; i
++) {
1413 getDirs().valueAt(i
)->print();
1416 const size_t NF
=getFiles().size();
1417 for (i
=0; i
<NF
; i
++) {
1418 getFiles().valueAt(i
)->print();
1422 String8
AaptDir::getPrintableSource() const
1424 if (mFiles
.size() > 0) {
1425 // Arbitrarily pull the first file out of the list as the source dir.
1426 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1428 if (mDirs
.size() > 0) {
1429 // Or arbitrarily pull the first dir out of the list as the source dir.
1430 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1433 // Should never hit this case, but to be safe...
1438 // =========================================================================
1439 // =========================================================================
1440 // =========================================================================
1442 sp
<AaptFile
> AaptAssets::addFile(
1443 const String8
& filePath
, const AaptGroupEntry
& entry
,
1444 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1445 const String8
& resType
)
1447 sp
<AaptDir
> dir
= this;
1448 sp
<AaptGroup
> group
;
1450 String8 root
, remain(filePath
), partialPath
;
1451 while (remain
.length() > 0) {
1452 root
= remain
.walkPath(&remain
);
1453 partialPath
.appendPath(root
);
1455 const String8
rootStr(root
);
1457 if (remain
.length() == 0) {
1458 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1460 group
= dir
->getFiles().valueAt(i
);
1462 group
= new AaptGroup(rootStr
, filePath
);
1463 status_t res
= dir
->addFile(rootStr
, group
);
1464 if (res
!= NO_ERROR
) {
1468 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1469 status_t res
= group
->addFile(file
);
1470 if (res
!= NO_ERROR
) {
1476 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1478 dir
= dir
->getDirs().valueAt(i
);
1480 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1481 status_t res
= dir
->addDir(rootStr
, subdir
);
1482 if (res
!= NO_ERROR
) {
1490 mGroupEntries
.add(entry
);
1491 if (outGroup
) *outGroup
= group
;
1495 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1496 const sp
<AaptFile
>& file
, const String8
& resType
)
1498 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1499 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1500 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1501 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1504 subdir
->addFile(leafName
, grr
);
1508 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1513 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1514 const size_t dirCount
=resDirs
.size();
1515 sp
<AaptAssets
> current
= this;
1517 const int N
= bundle
->getFileSpecCount();
1520 * If a package manifest was specified, include that first.
1522 if (bundle
->getAndroidManifestFile() != NULL
) {
1523 // place at root of zip.
1524 String8
srcFile(bundle
->getAndroidManifestFile());
1525 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1531 * If a directory of custom assets was supplied, slurp 'em up.
1533 if (bundle
->getAssetSourceDir()) {
1534 const char* assetDir
= bundle
->getAssetSourceDir();
1536 FileType type
= getFileType(assetDir
);
1537 if (type
== kFileTypeNonexistent
) {
1538 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1539 return UNKNOWN_ERROR
;
1541 if (type
!= kFileTypeDirectory
) {
1542 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1543 return UNKNOWN_ERROR
;
1546 String8
assetRoot(assetDir
);
1547 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1548 AaptGroupEntry group
;
1549 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1556 mGroupEntries
.add(group
);
1558 totalCount
+= count
;
1560 if (bundle
->getVerbose())
1561 printf("Found %d custom asset file%s in %s\n",
1562 count
, (count
==1) ? "" : "s", assetDir
);
1566 * If a directory of resource-specific assets was supplied, slurp 'em up.
1568 for (size_t i
=0; i
<dirCount
; i
++) {
1569 const char *res
= resDirs
[i
];
1571 type
= getFileType(res
);
1572 if (type
== kFileTypeNonexistent
) {
1573 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1574 return UNKNOWN_ERROR
;
1576 if (type
== kFileTypeDirectory
) {
1578 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1579 current
->setOverlay(nextOverlay
);
1580 current
= nextOverlay
;
1582 count
= current
->slurpResourceTree(bundle
, String8(res
));
1588 totalCount
+= count
;
1591 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1592 return UNKNOWN_ERROR
;
1598 * Now do any additional raw files.
1600 for (int arg
=0; arg
<N
; arg
++) {
1601 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1603 FileType type
= getFileType(assetDir
);
1604 if (type
== kFileTypeNonexistent
) {
1605 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1606 return UNKNOWN_ERROR
;
1608 if (type
!= kFileTypeDirectory
) {
1609 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1610 return UNKNOWN_ERROR
;
1613 String8
assetRoot(assetDir
);
1615 if (bundle
->getVerbose())
1616 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1619 * Do a recursive traversal of subdir tree. We don't make any
1620 * guarantees about ordering, so we're okay with an inorder search
1621 * using whatever order the OS happens to hand back to us.
1623 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1625 /* failure; report error and remove archive */
1629 totalCount
+= count
;
1631 if (bundle
->getVerbose())
1632 printf("Found %d asset file%s in %s\n",
1633 count
, (count
==1) ? "" : "s", assetDir
);
1637 if (count
!= NO_ERROR
) {
1647 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1648 const AaptGroupEntry
& kind
,
1649 const String8
& resType
)
1651 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1653 mGroupEntries
.add(kind
);
1659 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1663 DIR* dir
= opendir(srcDir
.string());
1665 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1666 return UNKNOWN_ERROR
;
1672 * Run through the directory, looking for dirs that match the
1676 struct dirent
* entry
= readdir(dir
);
1677 if (entry
== NULL
) {
1681 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1685 String8
subdirName(srcDir
);
1686 subdirName
.appendPath(entry
->d_name
);
1688 AaptGroupEntry group
;
1690 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1692 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1698 FileType type
= getFileType(subdirName
.string());
1700 if (type
== kFileTypeDirectory
) {
1701 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1702 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1709 mGroupEntries
.add(group
);
1715 if (bundle
->getVerbose()) {
1716 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1732 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1735 SortedVector
<AaptGroupEntry
> entries
;
1737 ZipFile
* zip
= new ZipFile
;
1738 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1739 if (err
!= NO_ERROR
) {
1740 fprintf(stderr
, "error opening zip file %s\n", filename
);
1746 const int N
= zip
->getNumEntries();
1747 for (int i
=0; i
<N
; i
++) {
1748 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1749 if (entry
->getDeleted()) {
1753 String8
entryName(entry
->getFileName());
1755 String8 dirName
= entryName
.getPathDir();
1756 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1759 AaptGroupEntry kind
;
1762 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1763 // these are the resources, pull their type out of the directory name
1764 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1766 // these are untyped and don't have an AaptGroupEntry
1768 if (entries
.indexOf(kind
) < 0) {
1770 mGroupEntries
.add(kind
);
1773 // use the one from the zip file if they both exist.
1774 dir
->removeFile(entryName
.getPathLeaf());
1776 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1777 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1778 if (err
!= NO_ERROR
) {
1779 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1783 file
->setCompressionMethod(entry
->getCompressionMethod());
1786 if (entryName
== "AndroidManifest.xml") {
1787 printf("AndroidManifest.xml\n");
1789 printf("\n\nfile: %s\n", entryName
.string());
1792 size_t len
= entry
->getUncompressedLen();
1793 void* data
= zip
->uncompress(entry
);
1794 void* buf
= file
->editData(len
);
1795 memcpy(buf
, data
, len
);
1799 const unsigned char* p
= (unsigned char*)data
;
1800 const unsigned char* end
= p
+len
;
1802 for (int i
=0; i
<32 && p
< end
; i
++) {
1803 printf("0x%03x ", i
*0x10 + OFF
);
1804 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1805 printf(" %02x", *p
);
1822 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1824 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1826 sym
= new AaptSymbols();
1827 mSymbols
.add(name
, sym
);
1832 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1834 if (!mHaveIncludedAssets
) {
1835 // Add in all includes.
1836 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1837 const size_t N
=incl
.size();
1838 for (size_t i
=0; i
<N
; i
++) {
1839 if (bundle
->getVerbose())
1840 printf("Including resources from package: %s\n", incl
[i
]);
1841 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1842 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1844 return UNKNOWN_ERROR
;
1847 mHaveIncludedAssets
= true;
1853 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1855 const ResTable
& res
= getIncludedResources();
1857 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1860 const ResTable
& AaptAssets::getIncludedResources() const
1862 return mIncludedAssets
.getResources(false);
1865 void AaptAssets::print() const
1867 printf("Locale/Vendor pairs:\n");
1868 const size_t N
=mGroupEntries
.size();
1869 for (size_t i
=0; i
<N
; i
++) {
1871 mGroupEntries
.itemAt(i
).locale
.string(),
1872 mGroupEntries
.itemAt(i
).vendor
.string());
1875 printf("\nFiles:\n");
1879 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
)
1881 const Vector
<sp
<AaptDir
> >& dirs
= mDirs
;
1882 const size_t N
= dirs
.size();
1883 for (size_t i
=0; i
<N
; i
++) {
1884 const sp
<AaptDir
>& d
= dirs
.itemAt(i
);
1885 if (d
->getLeaf() == name
) {
1893 valid_symbol_name(const String8
& symbol
)
1895 static char const * const KEYWORDS
[] = {
1896 "abstract", "assert", "boolean", "break",
1897 "byte", "case", "catch", "char", "class", "const", "continue",
1898 "default", "do", "double", "else", "enum", "extends", "final",
1899 "finally", "float", "for", "goto", "if", "implements", "import",
1900 "instanceof", "int", "interface", "long", "native", "new", "package",
1901 "private", "protected", "public", "return", "short", "static",
1902 "strictfp", "super", "switch", "synchronized", "this", "throw",
1903 "throws", "transient", "try", "void", "volatile", "while",
1904 "true", "false", "null",
1907 const char*const* k
= KEYWORDS
;
1908 const char*const s
= symbol
.string();
1910 if (0 == strcmp(s
, *k
)) {