]>
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 *type
= NULL
;
60 // Skip all hidden files.
62 // Skip ., .. and .svn but don't chatter about it.
63 if (strcmp(path
, ".") == 0
64 || strcmp(path
, "..") == 0
65 || strcmp(path
, ".svn") == 0) {
69 } else if (path
[0] == '_') {
70 // skip directories starting with _ (don't chatter about it)
71 String8
subdirName(root
);
72 subdirName
.appendPath(path
);
73 if (getFileType(subdirName
.string()) == kFileTypeDirectory
) {
76 } else if (strcmp(path
, "CVS") == 0) {
77 // Skip CVS but don't chatter about it.
79 } else if (strcasecmp(path
, "thumbs.db") == 0
80 || strcasecmp(path
, "picasa.ini") == 0) {
81 // Skip suspected image indexes files.
83 } else if (path
[strlen(path
)-1] == '~') {
84 // Skip suspected emacs backup files.
87 // Let everything else through.
91 /* If we get this far, "type" should be set and the file
94 String8
subdirName(root
);
95 subdirName
.appendPath(path
);
96 fprintf(stderr
, " (skipping %s %s '%s')\n", type
,
97 getFileType(subdirName
.string())==kFileTypeDirectory
? "dir":"file",
103 // =========================================================================
104 // =========================================================================
105 // =========================================================================
108 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
)
110 ResTable_config config
;
113 if (getMccName(part
.string(), &config
)) {
120 if (getMncName(part
.string(), &config
)) {
127 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
128 *axis
= AXIS_LANGUAGE
;
129 *value
= part
[1] << 8 | part
[0];
133 // locale - language_REGION
134 if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1])
135 && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) {
136 *axis
= AXIS_LANGUAGE
;
137 *value
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]);
141 // screen layout size
142 if (getScreenLayoutSizeName(part
.string(), &config
)) {
143 *axis
= AXIS_SCREENLAYOUTSIZE
;
144 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
148 // screen layout long
149 if (getScreenLayoutLongName(part
.string(), &config
)) {
150 *axis
= AXIS_SCREENLAYOUTLONG
;
151 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
156 if (getOrientationName(part
.string(), &config
)) {
157 *axis
= AXIS_ORIENTATION
;
158 *value
= config
.orientation
;
163 if (getDensityName(part
.string(), &config
)) {
164 *axis
= AXIS_DENSITY
;
165 *value
= config
.density
;
170 if (getTouchscreenName(part
.string(), &config
)) {
171 *axis
= AXIS_TOUCHSCREEN
;
172 *value
= config
.touchscreen
;
177 if (getKeysHiddenName(part
.string(), &config
)) {
178 *axis
= AXIS_KEYSHIDDEN
;
179 *value
= config
.inputFlags
;
184 if (getKeyboardName(part
.string(), &config
)) {
185 *axis
= AXIS_KEYBOARD
;
186 *value
= config
.keyboard
;
191 if (getNavigationName(part
.string(), &config
)) {
192 *axis
= AXIS_NAVIGATION
;
193 *value
= config
.navigation
;
198 if (getScreenSizeName(part
.string(), &config
)) {
199 *axis
= AXIS_SCREENSIZE
;
200 *value
= config
.screenSize
;
205 if (getVersionName(part
.string(), &config
)) {
206 *axis
= AXIS_VERSION
;
207 *value
= config
.version
;
215 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
217 Vector
<String8
> parts
;
219 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
220 String8 touch
, key
, keysHidden
, nav
, size
, vers
;
224 while (NULL
!= (q
= strchr(p
, '-'))) {
228 //printf("part: %s\n", parts[parts.size()-1].string());
234 //printf("part: %s\n", parts[parts.size()-1].string());
236 const int N
= parts
.size();
238 String8 part
= parts
[index
];
241 if (!isValidResourceType(part
)) {
253 if (getMccName(part
.string())) {
262 //printf("not mcc: %s\n", part.string());
266 if (getMncName(part
.string())) {
275 //printf("not mcc: %s\n", part.string());
279 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
288 //printf("not language: %s\n", part.string());
293 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
296 loc
+= part
.string() + 1;
304 //printf("not region: %s\n", part.string());
307 if (getScreenLayoutSizeName(part
.string())) {
316 //printf("not screen layout size: %s\n", part.string());
319 if (getScreenLayoutLongName(part
.string())) {
328 //printf("not screen layout long: %s\n", part.string());
332 if (getOrientationName(part
.string())) {
341 //printf("not orientation: %s\n", part.string());
345 if (getDensityName(part
.string())) {
354 //printf("not density: %s\n", part.string());
358 if (getTouchscreenName(part
.string())) {
367 //printf("not touchscreen: %s\n", part.string());
371 if (getKeysHiddenName(part
.string())) {
380 //printf("not keysHidden: %s\n", part.string());
384 if (getKeyboardName(part
.string())) {
393 //printf("not keyboard: %s\n", part.string());
396 if (getNavigationName(part
.string())) {
405 //printf("not navigation: %s\n", part.string());
408 if (getScreenSizeName(part
.string())) {
417 //printf("not screen size: %s\n", part.string());
420 if (getVersionName(part
.string())) {
429 //printf("not version: %s\n", part.string());
432 // if there are extra parts, it doesn't match
439 this->screenLayoutSize
= layoutsize
;
440 this->screenLayoutLong
= layoutlong
;
441 this->orientation
= orient
;
443 this->touchscreen
= touch
;
444 this->keysHidden
= keysHidden
;
445 this->keyboard
= key
;
446 this->navigation
= nav
;
447 this->screenSize
= size
;
448 this->version
= vers
;
450 // what is this anyway?
457 AaptGroupEntry::toString() const
459 String8 s
= this->mcc
;
465 s
+= screenLayoutSize
;
467 s
+= screenLayoutLong
;
469 s
+= this->orientation
;
488 AaptGroupEntry::toDirName(const String8
& resType
) const
491 if (this->mcc
!= "") {
495 if (this->mnc
!= "") {
499 if (this->locale
!= "") {
503 if (this->screenLayoutSize
!= "") {
505 s
+= screenLayoutSize
;
507 if (this->screenLayoutLong
!= "") {
509 s
+= screenLayoutLong
;
511 if (this->orientation
!= "") {
515 if (this->density
!= "") {
519 if (this->touchscreen
!= "") {
523 if (this->keysHidden
!= "") {
527 if (this->keyboard
!= "") {
531 if (this->navigation
!= "") {
535 if (this->screenSize
!= "") {
539 if (this->version
!= "") {
547 bool AaptGroupEntry::getMccName(const char* name
,
548 ResTable_config
* out
)
550 if (strcmp(name
, kWildcardName
) == 0) {
551 if (out
) out
->mcc
= 0;
554 const char* c
= name
;
555 if (tolower(*c
) != 'm') return false;
557 if (tolower(*c
) != 'c') return false;
559 if (tolower(*c
) != 'c') return false;
564 while (*c
>= '0' && *c
<= '9') {
567 if (*c
!= 0) return false;
568 if (c
-val
!= 3) return false;
572 if (out
) out
->mcc
= d
;
579 bool AaptGroupEntry::getMncName(const char* name
,
580 ResTable_config
* out
)
582 if (strcmp(name
, kWildcardName
) == 0) {
583 if (out
) out
->mcc
= 0;
586 const char* c
= name
;
587 if (tolower(*c
) != 'm') return false;
589 if (tolower(*c
) != 'n') return false;
591 if (tolower(*c
) != 'c') return false;
596 while (*c
>= '0' && *c
<= '9') {
599 if (*c
!= 0) return false;
600 if (c
-val
== 0 || c
-val
> 3) return false;
604 if (out
) out
->mnc
= d
;
612 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
615 * TODO: Should insist that the first two letters are lower case, and the
616 * second two are upper.
618 bool AaptGroupEntry::getLocaleName(const char* fileName
,
619 ResTable_config
* out
)
621 if (strcmp(fileName
, kWildcardName
) == 0
622 || strcmp(fileName
, kDefaultLocale
) == 0) {
624 out
->language
[0] = 0;
625 out
->language
[1] = 0;
632 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
634 out
->language
[0] = fileName
[0];
635 out
->language
[1] = fileName
[1];
642 if (strlen(fileName
) == 5 &&
643 isalpha(fileName
[0]) &&
644 isalpha(fileName
[1]) &&
645 fileName
[2] == '-' &&
646 isalpha(fileName
[3]) &&
647 isalpha(fileName
[4])) {
649 out
->language
[0] = fileName
[0];
650 out
->language
[1] = fileName
[1];
651 out
->country
[0] = fileName
[3];
652 out
->country
[1] = fileName
[4];
660 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
661 ResTable_config
* out
)
663 if (strcmp(name
, kWildcardName
) == 0) {
664 if (out
) out
->screenLayout
=
665 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
666 | ResTable_config::SCREENSIZE_ANY
;
668 } else if (strcmp(name
, "small") == 0) {
669 if (out
) out
->screenLayout
=
670 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
671 | ResTable_config::SCREENSIZE_SMALL
;
673 } else if (strcmp(name
, "normal") == 0) {
674 if (out
) out
->screenLayout
=
675 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
676 | ResTable_config::SCREENSIZE_NORMAL
;
678 } else if (strcmp(name
, "large") == 0) {
679 if (out
) out
->screenLayout
=
680 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
681 | ResTable_config::SCREENSIZE_LARGE
;
688 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
689 ResTable_config
* out
)
691 if (strcmp(name
, kWildcardName
) == 0) {
692 if (out
) out
->screenLayout
=
693 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
694 | ResTable_config::SCREENLONG_ANY
;
696 } else if (strcmp(name
, "long") == 0) {
697 if (out
) out
->screenLayout
=
698 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
699 | ResTable_config::SCREENLONG_YES
;
701 } else if (strcmp(name
, "notlong") == 0) {
702 if (out
) out
->screenLayout
=
703 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
704 | ResTable_config::SCREENLONG_NO
;
711 bool AaptGroupEntry::getOrientationName(const char* name
,
712 ResTable_config
* out
)
714 if (strcmp(name
, kWildcardName
) == 0) {
715 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
717 } else if (strcmp(name
, "port") == 0) {
718 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
720 } else if (strcmp(name
, "land") == 0) {
721 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
723 } else if (strcmp(name
, "square") == 0) {
724 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
731 bool AaptGroupEntry::getDensityName(const char* name
,
732 ResTable_config
* out
)
734 if (strcmp(name
, kWildcardName
) == 0) {
735 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
739 if (strcmp(name
, "nodpi") == 0) {
740 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
744 if (strcmp(name
, "ldpi") == 0) {
745 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
749 if (strcmp(name
, "mdpi") == 0) {
750 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
754 if (strcmp(name
, "hdpi") == 0) {
755 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
759 char* c
= (char*)name
;
760 while (*c
>= '0' && *c
<= '9') {
764 // check that we have 'dpi' after the last digit.
765 if (toupper(c
[0]) != 'D' ||
766 toupper(c
[1]) != 'P' ||
767 toupper(c
[2]) != 'I' ||
772 // temporarily replace the first letter with \0 to
781 if (out
) out
->density
= d
;
788 bool AaptGroupEntry::getTouchscreenName(const char* name
,
789 ResTable_config
* out
)
791 if (strcmp(name
, kWildcardName
) == 0) {
792 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
794 } else if (strcmp(name
, "notouch") == 0) {
795 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
797 } else if (strcmp(name
, "stylus") == 0) {
798 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
800 } else if (strcmp(name
, "finger") == 0) {
801 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
808 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
809 ResTable_config
* out
)
813 if (strcmp(name
, kWildcardName
) == 0) {
814 mask
= out
->MASK_KEYSHIDDEN
;
815 value
= out
->KEYSHIDDEN_ANY
;
816 } else if (strcmp(name
, "keysexposed") == 0) {
817 mask
= out
->MASK_KEYSHIDDEN
;
818 value
= out
->KEYSHIDDEN_NO
;
819 } else if (strcmp(name
, "keyshidden") == 0) {
820 mask
= out
->MASK_KEYSHIDDEN
;
821 value
= out
->KEYSHIDDEN_YES
;
822 } else if (strcmp(name
, "keyssoft") == 0) {
823 mask
= out
->MASK_KEYSHIDDEN
;
824 value
= out
->KEYSHIDDEN_SOFT
;
828 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
835 bool AaptGroupEntry::getKeyboardName(const char* name
,
836 ResTable_config
* out
)
838 if (strcmp(name
, kWildcardName
) == 0) {
839 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
841 } else if (strcmp(name
, "nokeys") == 0) {
842 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
844 } else if (strcmp(name
, "qwerty") == 0) {
845 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
847 } else if (strcmp(name
, "12key") == 0) {
848 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
855 bool AaptGroupEntry::getNavigationName(const char* name
,
856 ResTable_config
* out
)
858 if (strcmp(name
, kWildcardName
) == 0) {
859 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
861 } else if (strcmp(name
, "nonav") == 0) {
862 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
864 } else if (strcmp(name
, "dpad") == 0) {
865 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
867 } else if (strcmp(name
, "trackball") == 0) {
868 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
870 } else if (strcmp(name
, "wheel") == 0) {
871 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
878 bool AaptGroupEntry::getScreenSizeName(const char* name
,
879 ResTable_config
* out
)
881 if (strcmp(name
, kWildcardName
) == 0) {
883 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
884 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
889 const char* x
= name
;
890 while (*x
>= '0' && *x
<= '9') x
++;
891 if (x
== name
|| *x
!= 'x') return false;
892 String8
xName(name
, x
-name
);
896 while (*y
>= '0' && *y
<= '9') y
++;
897 if (y
== name
|| *y
!= 0) return false;
898 String8
yName(x
, y
-x
);
900 uint16_t w
= (uint16_t)atoi(xName
.string());
901 uint16_t h
= (uint16_t)atoi(yName
.string());
907 out
->screenWidth
= w
;
908 out
->screenHeight
= h
;
914 bool AaptGroupEntry::getVersionName(const char* name
,
915 ResTable_config
* out
)
917 if (strcmp(name
, kWildcardName
) == 0) {
919 out
->sdkVersion
= out
->SDKVERSION_ANY
;
920 out
->minorVersion
= out
->MINORVERSION_ANY
;
930 const char* s
= name
;
931 while (*s
>= '0' && *s
<= '9') s
++;
932 if (s
== name
|| *s
!= 0) return false;
933 String8
sdkName(name
, s
-name
);
936 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
937 out
->minorVersion
= 0;
943 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
945 int v
= mcc
.compare(o
.mcc
);
946 if (v
== 0) v
= mnc
.compare(o
.mnc
);
947 if (v
== 0) v
= locale
.compare(o
.locale
);
948 if (v
== 0) v
= vendor
.compare(o
.vendor
);
949 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
950 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
951 if (v
== 0) v
= orientation
.compare(o
.orientation
);
952 if (v
== 0) v
= density
.compare(o
.density
);
953 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
954 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
955 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
956 if (v
== 0) v
= navigation
.compare(o
.navigation
);
957 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
958 if (v
== 0) v
= version
.compare(o
.version
);
962 ResTable_config
AaptGroupEntry::toParams() const
964 ResTable_config params
;
965 memset(¶ms
, 0, sizeof(params
));
966 getMccName(mcc
.string(), ¶ms
);
967 getMncName(mnc
.string(), ¶ms
);
968 getLocaleName(locale
.string(), ¶ms
);
969 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
970 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
971 getOrientationName(orientation
.string(), ¶ms
);
972 getDensityName(density
.string(), ¶ms
);
973 getTouchscreenName(touchscreen
.string(), ¶ms
);
974 getKeysHiddenName(keysHidden
.string(), ¶ms
);
975 getKeyboardName(keyboard
.string(), ¶ms
);
976 getNavigationName(navigation
.string(), ¶ms
);
977 getScreenSizeName(screenSize
.string(), ¶ms
);
978 getVersionName(version
.string(), ¶ms
);
982 // =========================================================================
983 // =========================================================================
984 // =========================================================================
986 void* AaptFile::editData(size_t size
)
988 if (size
<= mBufferSize
) {
992 size_t allocSize
= (size
*3)/2;
993 void* buf
= realloc(mData
, allocSize
);
999 mBufferSize
= allocSize
;
1003 void* AaptFile::editData(size_t* outSize
)
1006 *outSize
= mDataSize
;
1011 void* AaptFile::padData(size_t wordSize
)
1013 const size_t extra
= mDataSize%wordSize
;
1018 size_t initial
= mDataSize
;
1019 void* data
= editData(initial
+(wordSize
-extra
));
1021 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1026 status_t
AaptFile::writeData(const void* data
, size_t size
)
1028 size_t end
= mDataSize
;
1029 size_t total
= size
+ end
;
1030 void* buf
= editData(total
);
1032 return UNKNOWN_ERROR
;
1034 memcpy(((char*)buf
)+end
, data
, size
);
1038 void AaptFile::clearData()
1040 if (mData
!= NULL
) free(mData
);
1046 String8
AaptFile::getPrintableSource() const
1049 String8
name(mGroupEntry
.locale
.string());
1050 name
.appendPath(mGroupEntry
.vendor
.string());
1051 name
.appendPath(mPath
);
1052 name
.append(" #generated");
1058 // =========================================================================
1059 // =========================================================================
1060 // =========================================================================
1062 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1064 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1065 file
->mPath
= mPath
;
1066 mFiles
.add(file
->getGroupEntry(), file
);
1070 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1071 getPrintableSource().string());
1072 return UNKNOWN_ERROR
;
1075 void AaptGroup::removeFile(size_t index
)
1077 mFiles
.removeItemsAt(index
);
1080 void AaptGroup::print() const
1082 printf(" %s\n", getPath().string());
1083 const size_t N
=mFiles
.size();
1085 for (i
=0; i
<N
; i
++) {
1086 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1087 const AaptGroupEntry
& e
= file
->getGroupEntry();
1088 if (file
->hasData()) {
1089 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
1090 (int)file
->getSize());
1092 printf(" Src: %s\n", file
->getPrintableSource().string());
1097 String8
AaptGroup::getPrintableSource() const
1099 if (mFiles
.size() > 0) {
1100 // Arbitrarily pull the first source file out of the list.
1101 return mFiles
.valueAt(0)->getPrintableSource();
1104 // Should never hit this case, but to be safe...
1109 // =========================================================================
1110 // =========================================================================
1111 // =========================================================================
1113 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1115 if (mFiles
.indexOfKey(name
) >= 0) {
1116 return ALREADY_EXISTS
;
1118 mFiles
.add(name
, file
);
1122 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1124 if (mDirs
.indexOfKey(name
) >= 0) {
1125 return ALREADY_EXISTS
;
1127 mDirs
.add(name
, dir
);
1131 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1134 String8 remain
= path
;
1136 sp
<AaptDir
> subdir
= this;
1137 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1138 subdir
= subdir
->makeDir(name
);
1141 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1143 return subdir
->mDirs
.valueAt(i
);
1145 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1146 subdir
->mDirs
.add(name
, dir
);
1150 void AaptDir::removeFile(const String8
& name
)
1152 mFiles
.removeItem(name
);
1155 void AaptDir::removeDir(const String8
& name
)
1157 mDirs
.removeItem(name
);
1160 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1162 sp
<AaptGroup
> origGroup
;
1164 // Find and remove the given file with shear, brute force!
1165 const size_t NG
= mFiles
.size();
1167 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1168 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1169 const size_t NF
= g
->getFiles().size();
1170 for (size_t j
=0; j
<NF
; j
++) {
1171 if (g
->getFiles().valueAt(j
) == file
) {
1175 mFiles
.removeItemsAt(i
);
1182 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1184 // Place the file under its new name.
1185 if (origGroup
!= NULL
) {
1186 return addLeafFile(newName
, file
);
1192 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1194 sp
<AaptGroup
> group
;
1195 if (mFiles
.indexOfKey(leafName
) >= 0) {
1196 group
= mFiles
.valueFor(leafName
);
1198 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1199 mFiles
.add(leafName
, group
);
1202 return group
->addFile(file
);
1205 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1206 const AaptGroupEntry
& kind
, const String8
& resType
)
1208 Vector
<String8
> fileNames
;
1213 dir
= opendir(srcDir
.string());
1215 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1216 return UNKNOWN_ERROR
;
1220 * Slurp the filenames out of the directory.
1223 struct dirent
* entry
;
1225 entry
= readdir(dir
);
1229 if (isHidden(srcDir
.string(), entry
->d_name
))
1232 fileNames
.add(String8(entry
->d_name
));
1241 * Stash away the files and recursively descend into subdirectories.
1243 const size_t N
= fileNames
.size();
1245 for (i
= 0; i
< N
; i
++) {
1246 String8
pathName(srcDir
);
1249 pathName
.appendPath(fileNames
[i
].string());
1250 type
= getFileType(pathName
.string());
1251 if (type
== kFileTypeDirectory
) {
1253 bool notAdded
= false;
1254 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1255 subdir
= mDirs
.valueFor(fileNames
[i
]);
1257 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1260 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1262 if (res
< NO_ERROR
) {
1265 if (res
> 0 && notAdded
) {
1266 mDirs
.add(fileNames
[i
], subdir
);
1269 } else if (type
== kFileTypeRegular
) {
1270 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1271 status_t err
= addLeafFile(fileNames
[i
], file
);
1272 if (err
!= NO_ERROR
) {
1279 if (bundle
->getVerbose())
1280 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1287 status_t
AaptDir::validate() const
1289 const size_t NF
= mFiles
.size();
1290 const size_t ND
= mDirs
.size();
1292 for (i
= 0; i
< NF
; i
++) {
1293 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1294 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1295 "Invalid filename. Unable to add.");
1296 return UNKNOWN_ERROR
;
1300 for (j
= i
+1; j
< NF
; j
++) {
1301 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1302 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1303 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1304 "File is case-insensitive equivalent to: %s",
1305 mFiles
.valueAt(j
)->getPrintableSource().string());
1306 return UNKNOWN_ERROR
;
1309 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1310 // (this is mostly caught by the "marked" stuff, below)
1313 for (j
= 0; j
< ND
; j
++) {
1314 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1315 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1316 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1317 "File conflicts with dir from: %s",
1318 mDirs
.valueAt(j
)->getPrintableSource().string());
1319 return UNKNOWN_ERROR
;
1324 for (i
= 0; i
< ND
; i
++) {
1325 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1326 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1327 "Invalid directory name, unable to add.");
1328 return UNKNOWN_ERROR
;
1332 for (j
= i
+1; j
< ND
; j
++) {
1333 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1334 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1335 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1336 "Directory is case-insensitive equivalent to: %s",
1337 mDirs
.valueAt(j
)->getPrintableSource().string());
1338 return UNKNOWN_ERROR
;
1342 status_t err
= mDirs
.valueAt(i
)->validate();
1343 if (err
!= NO_ERROR
) {
1351 void AaptDir::print() const
1353 const size_t ND
=getDirs().size();
1355 for (i
=0; i
<ND
; i
++) {
1356 getDirs().valueAt(i
)->print();
1359 const size_t NF
=getFiles().size();
1360 for (i
=0; i
<NF
; i
++) {
1361 getFiles().valueAt(i
)->print();
1365 String8
AaptDir::getPrintableSource() const
1367 if (mFiles
.size() > 0) {
1368 // Arbitrarily pull the first file out of the list as the source dir.
1369 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1371 if (mDirs
.size() > 0) {
1372 // Or arbitrarily pull the first dir out of the list as the source dir.
1373 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1376 // Should never hit this case, but to be safe...
1381 // =========================================================================
1382 // =========================================================================
1383 // =========================================================================
1385 sp
<AaptFile
> AaptAssets::addFile(
1386 const String8
& filePath
, const AaptGroupEntry
& entry
,
1387 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1388 const String8
& resType
)
1390 sp
<AaptDir
> dir
= this;
1391 sp
<AaptGroup
> group
;
1393 String8 root
, remain(filePath
), partialPath
;
1394 while (remain
.length() > 0) {
1395 root
= remain
.walkPath(&remain
);
1396 partialPath
.appendPath(root
);
1398 const String8
rootStr(root
);
1400 if (remain
.length() == 0) {
1401 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1403 group
= dir
->getFiles().valueAt(i
);
1405 group
= new AaptGroup(rootStr
, filePath
);
1406 status_t res
= dir
->addFile(rootStr
, group
);
1407 if (res
!= NO_ERROR
) {
1411 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1412 status_t res
= group
->addFile(file
);
1413 if (res
!= NO_ERROR
) {
1419 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1421 dir
= dir
->getDirs().valueAt(i
);
1423 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1424 status_t res
= dir
->addDir(rootStr
, subdir
);
1425 if (res
!= NO_ERROR
) {
1433 mGroupEntries
.add(entry
);
1434 if (outGroup
) *outGroup
= group
;
1438 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1439 const sp
<AaptFile
>& file
, const String8
& resType
)
1441 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1442 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1443 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1444 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1447 subdir
->addFile(leafName
, grr
);
1451 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1456 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1457 const size_t dirCount
=resDirs
.size();
1458 sp
<AaptAssets
> current
= this;
1460 const int N
= bundle
->getFileSpecCount();
1463 * If a package manifest was specified, include that first.
1465 if (bundle
->getAndroidManifestFile() != NULL
) {
1466 // place at root of zip.
1467 String8
srcFile(bundle
->getAndroidManifestFile());
1468 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1474 * If a directory of custom assets was supplied, slurp 'em up.
1476 if (bundle
->getAssetSourceDir()) {
1477 const char* assetDir
= bundle
->getAssetSourceDir();
1479 FileType type
= getFileType(assetDir
);
1480 if (type
== kFileTypeNonexistent
) {
1481 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1482 return UNKNOWN_ERROR
;
1484 if (type
!= kFileTypeDirectory
) {
1485 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1486 return UNKNOWN_ERROR
;
1489 String8
assetRoot(assetDir
);
1490 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1491 AaptGroupEntry group
;
1492 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1499 mGroupEntries
.add(group
);
1501 totalCount
+= count
;
1503 if (bundle
->getVerbose())
1504 printf("Found %d custom asset file%s in %s\n",
1505 count
, (count
==1) ? "" : "s", assetDir
);
1509 * If a directory of resource-specific assets was supplied, slurp 'em up.
1511 for (size_t i
=0; i
<dirCount
; i
++) {
1512 const char *res
= resDirs
[i
];
1514 type
= getFileType(res
);
1515 if (type
== kFileTypeNonexistent
) {
1516 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1517 return UNKNOWN_ERROR
;
1519 if (type
== kFileTypeDirectory
) {
1521 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1522 current
->setOverlay(nextOverlay
);
1523 current
= nextOverlay
;
1525 count
= current
->slurpResourceTree(bundle
, String8(res
));
1531 totalCount
+= count
;
1534 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1535 return UNKNOWN_ERROR
;
1541 * Now do any additional raw files.
1543 for (int arg
=0; arg
<N
; arg
++) {
1544 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1546 FileType type
= getFileType(assetDir
);
1547 if (type
== kFileTypeNonexistent
) {
1548 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1549 return UNKNOWN_ERROR
;
1551 if (type
!= kFileTypeDirectory
) {
1552 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1553 return UNKNOWN_ERROR
;
1556 String8
assetRoot(assetDir
);
1558 if (bundle
->getVerbose())
1559 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1562 * Do a recursive traversal of subdir tree. We don't make any
1563 * guarantees about ordering, so we're okay with an inorder search
1564 * using whatever order the OS happens to hand back to us.
1566 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1568 /* failure; report error and remove archive */
1572 totalCount
+= count
;
1574 if (bundle
->getVerbose())
1575 printf("Found %d asset file%s in %s\n",
1576 count
, (count
==1) ? "" : "s", assetDir
);
1580 if (count
!= NO_ERROR
) {
1590 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1591 const AaptGroupEntry
& kind
,
1592 const String8
& resType
)
1594 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1596 mGroupEntries
.add(kind
);
1602 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1606 DIR* dir
= opendir(srcDir
.string());
1608 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1609 return UNKNOWN_ERROR
;
1615 * Run through the directory, looking for dirs that match the
1619 struct dirent
* entry
= readdir(dir
);
1620 if (entry
== NULL
) {
1624 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1628 String8
subdirName(srcDir
);
1629 subdirName
.appendPath(entry
->d_name
);
1631 AaptGroupEntry group
;
1633 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1635 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1641 FileType type
= getFileType(subdirName
.string());
1643 if (type
== kFileTypeDirectory
) {
1644 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1645 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1652 mGroupEntries
.add(group
);
1658 if (bundle
->getVerbose()) {
1659 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1675 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1678 SortedVector
<AaptGroupEntry
> entries
;
1680 ZipFile
* zip
= new ZipFile
;
1681 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1682 if (err
!= NO_ERROR
) {
1683 fprintf(stderr
, "error opening zip file %s\n", filename
);
1689 const int N
= zip
->getNumEntries();
1690 for (int i
=0; i
<N
; i
++) {
1691 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1692 if (entry
->getDeleted()) {
1696 String8
entryName(entry
->getFileName());
1698 String8 dirName
= entryName
.getPathDir();
1699 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1702 AaptGroupEntry kind
;
1705 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1706 // these are the resources, pull their type out of the directory name
1707 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1709 // these are untyped and don't have an AaptGroupEntry
1711 if (entries
.indexOf(kind
) < 0) {
1713 mGroupEntries
.add(kind
);
1716 // use the one from the zip file if they both exist.
1717 dir
->removeFile(entryName
.getPathLeaf());
1719 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1720 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1721 if (err
!= NO_ERROR
) {
1722 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1726 file
->setCompressionMethod(entry
->getCompressionMethod());
1729 if (entryName
== "AndroidManifest.xml") {
1730 printf("AndroidManifest.xml\n");
1732 printf("\n\nfile: %s\n", entryName
.string());
1735 size_t len
= entry
->getUncompressedLen();
1736 void* data
= zip
->uncompress(entry
);
1737 void* buf
= file
->editData(len
);
1738 memcpy(buf
, data
, len
);
1742 const unsigned char* p
= (unsigned char*)data
;
1743 const unsigned char* end
= p
+len
;
1745 for (int i
=0; i
<32 && p
< end
; i
++) {
1746 printf("0x%03x ", i
*0x10 + OFF
);
1747 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1748 printf(" %02x", *p
);
1765 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1767 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1769 sym
= new AaptSymbols();
1770 mSymbols
.add(name
, sym
);
1775 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1777 if (!mHaveIncludedAssets
) {
1778 // Add in all includes.
1779 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1780 const size_t N
=incl
.size();
1781 for (size_t i
=0; i
<N
; i
++) {
1782 if (bundle
->getVerbose())
1783 printf("Including resources from package: %s\n", incl
[i
]);
1784 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1785 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1787 return UNKNOWN_ERROR
;
1790 mHaveIncludedAssets
= true;
1796 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1798 const ResTable
& res
= getIncludedResources();
1800 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1803 const ResTable
& AaptAssets::getIncludedResources() const
1805 return mIncludedAssets
.getResources(false);
1808 void AaptAssets::print() const
1810 printf("Locale/Vendor pairs:\n");
1811 const size_t N
=mGroupEntries
.size();
1812 for (size_t i
=0; i
<N
; i
++) {
1814 mGroupEntries
.itemAt(i
).locale
.string(),
1815 mGroupEntries
.itemAt(i
).vendor
.string());
1818 printf("\nFiles:\n");
1823 valid_symbol_name(const String8
& symbol
)
1825 static char const * const KEYWORDS
[] = {
1826 "abstract", "assert", "boolean", "break",
1827 "byte", "case", "catch", "char", "class", "const", "continue",
1828 "default", "do", "double", "else", "enum", "extends", "final",
1829 "finally", "float", "for", "goto", "if", "implements", "import",
1830 "instanceof", "int", "interface", "long", "native", "new", "package",
1831 "private", "protected", "public", "return", "short", "static",
1832 "strictfp", "super", "switch", "synchronized", "this", "throw",
1833 "throws", "transient", "try", "void", "volatile", "while",
1834 "true", "false", "null",
1837 const char*const* k
= KEYWORDS
;
1838 const char*const s
= symbol
.string();
1840 if (0 == strcmp(s
, *k
)) {