]>
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]);
142 if (getOrientationName(part
.string(), &config
)) {
143 *axis
= AXIS_ORIENTATION
;
144 *value
= config
.orientation
;
149 if (getDensityName(part
.string(), &config
)) {
150 *axis
= AXIS_DENSITY
;
151 *value
= config
.density
;
156 if (getTouchscreenName(part
.string(), &config
)) {
157 *axis
= AXIS_TOUCHSCREEN
;
158 *value
= config
.touchscreen
;
163 if (getKeysHiddenName(part
.string(), &config
)) {
164 *axis
= AXIS_KEYSHIDDEN
;
165 *value
= config
.inputFlags
;
170 if (getKeyboardName(part
.string(), &config
)) {
171 *axis
= AXIS_KEYBOARD
;
172 *value
= config
.keyboard
;
177 if (getNavigationName(part
.string(), &config
)) {
178 *axis
= AXIS_NAVIGATION
;
179 *value
= config
.navigation
;
184 if (getScreenSizeName(part
.string(), &config
)) {
185 *axis
= AXIS_SCREENSIZE
;
186 *value
= config
.screenSize
;
191 if (getScreenLayoutName(part
.string(), &config
)) {
192 *axis
= AXIS_SCREENLAYOUT
;
193 *value
= config
.screenLayout
;
198 if (getVersionName(part
.string(), &config
)) {
199 *axis
= AXIS_VERSION
;
200 *value
= config
.version
;
208 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
210 Vector
<String8
> parts
;
212 String8 mcc
, mnc
, loc
, orient
, den
, touch
, key
, keysHidden
, nav
, size
, layout
, vers
;
216 while (NULL
!= (q
= strchr(p
, '-'))) {
220 //printf("part: %s\n", parts[parts.size()-1].string());
226 //printf("part: %s\n", parts[parts.size()-1].string());
228 const int N
= parts
.size();
230 String8 part
= parts
[index
];
233 if (!isValidResourceType(part
)) {
245 if (getMccName(part
.string())) {
254 //printf("not mcc: %s\n", part.string());
258 if (getMncName(part
.string())) {
267 //printf("not mcc: %s\n", part.string());
271 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
280 //printf("not language: %s\n", part.string());
285 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
288 loc
+= part
.string() + 1;
296 //printf("not region: %s\n", part.string());
300 if (getOrientationName(part
.string())) {
309 //printf("not orientation: %s\n", part.string());
313 if (getDensityName(part
.string())) {
322 //printf("not density: %s\n", part.string());
326 if (getTouchscreenName(part
.string())) {
335 //printf("not touchscreen: %s\n", part.string());
339 if (getKeysHiddenName(part
.string())) {
348 //printf("not keysHidden: %s\n", part.string());
352 if (getKeyboardName(part
.string())) {
361 //printf("not keyboard: %s\n", part.string());
364 if (getNavigationName(part
.string())) {
373 //printf("not navigation: %s\n", part.string());
376 if (getScreenSizeName(part
.string())) {
385 //printf("not screen size: %s\n", part.string());
388 if (getScreenLayoutName(part
.string())) {
397 //printf("not screen layout: %s\n", part.string());
400 if (getVersionName(part
.string())) {
409 //printf("not version: %s\n", part.string());
412 // if there are extra parts, it doesn't match
419 this->orientation
= orient
;
421 this->touchscreen
= touch
;
422 this->keysHidden
= keysHidden
;
423 this->keyboard
= key
;
424 this->navigation
= nav
;
425 this->screenSize
= size
;
426 this->screenLayout
= layout
;
427 this->version
= vers
;
429 // what is this anyway?
436 AaptGroupEntry::toString() const
438 String8 s
= this->mcc
;
444 s
+= this->orientation
;
465 AaptGroupEntry::toDirName(const String8
& resType
) const
468 if (this->mcc
!= "") {
472 if (this->mnc
!= "") {
476 if (this->locale
!= "") {
480 if (this->orientation
!= "") {
484 if (this->density
!= "") {
488 if (this->touchscreen
!= "") {
492 if (this->keysHidden
!= "") {
496 if (this->keyboard
!= "") {
500 if (this->navigation
!= "") {
504 if (this->screenSize
!= "") {
508 if (this->screenLayout
!= "") {
512 if (this->version
!= "") {
520 bool AaptGroupEntry::getMccName(const char* name
,
521 ResTable_config
* out
)
523 if (strcmp(name
, kWildcardName
) == 0) {
524 if (out
) out
->mcc
= 0;
527 const char* c
= name
;
528 if (tolower(*c
) != 'm') return false;
530 if (tolower(*c
) != 'c') return false;
532 if (tolower(*c
) != 'c') return false;
537 while (*c
>= '0' && *c
<= '9') {
540 if (*c
!= 0) return false;
541 if (c
-val
!= 3) return false;
545 if (out
) out
->mcc
= d
;
552 bool AaptGroupEntry::getMncName(const char* name
,
553 ResTable_config
* out
)
555 if (strcmp(name
, kWildcardName
) == 0) {
556 if (out
) out
->mcc
= 0;
559 const char* c
= name
;
560 if (tolower(*c
) != 'm') return false;
562 if (tolower(*c
) != 'n') return false;
564 if (tolower(*c
) != 'c') return false;
569 while (*c
>= '0' && *c
<= '9') {
572 if (*c
!= 0) return false;
573 if (c
-val
== 0 || c
-val
> 3) return false;
577 if (out
) out
->mnc
= d
;
585 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
588 * TODO: Should insist that the first two letters are lower case, and the
589 * second two are upper.
591 bool AaptGroupEntry::getLocaleName(const char* fileName
,
592 ResTable_config
* out
)
594 if (strcmp(fileName
, kWildcardName
) == 0
595 || strcmp(fileName
, kDefaultLocale
) == 0) {
597 out
->language
[0] = 0;
598 out
->language
[1] = 0;
605 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
607 out
->language
[0] = fileName
[0];
608 out
->language
[1] = fileName
[1];
615 if (strlen(fileName
) == 5 &&
616 isalpha(fileName
[0]) &&
617 isalpha(fileName
[1]) &&
618 fileName
[2] == '-' &&
619 isalpha(fileName
[3]) &&
620 isalpha(fileName
[4])) {
622 out
->language
[0] = fileName
[0];
623 out
->language
[1] = fileName
[1];
624 out
->country
[0] = fileName
[3];
625 out
->country
[1] = fileName
[4];
633 bool AaptGroupEntry::getOrientationName(const char* name
,
634 ResTable_config
* out
)
636 if (strcmp(name
, kWildcardName
) == 0) {
637 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
639 } else if (strcmp(name
, "port") == 0) {
640 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
642 } else if (strcmp(name
, "land") == 0) {
643 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
645 } else if (strcmp(name
, "square") == 0) {
646 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
653 bool AaptGroupEntry::getDensityName(const char* name
,
654 ResTable_config
* out
)
656 if (strcmp(name
, kWildcardName
) == 0) {
657 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
661 if (strcmp(name
, "nodpi") == 0) {
662 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
666 char* c
= (char*)name
;
667 while (*c
>= '0' && *c
<= '9') {
671 // check that we have 'dpi' after the last digit.
672 if (toupper(c
[0]) != 'D' ||
673 toupper(c
[1]) != 'P' ||
674 toupper(c
[2]) != 'I' ||
679 // temporarily replace the first letter with \0 to
688 if (out
) out
->density
= d
;
695 bool AaptGroupEntry::getTouchscreenName(const char* name
,
696 ResTable_config
* out
)
698 if (strcmp(name
, kWildcardName
) == 0) {
699 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
701 } else if (strcmp(name
, "notouch") == 0) {
702 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
704 } else if (strcmp(name
, "stylus") == 0) {
705 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
707 } else if (strcmp(name
, "finger") == 0) {
708 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
715 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
716 ResTable_config
* out
)
720 if (strcmp(name
, kWildcardName
) == 0) {
721 mask
= out
->MASK_KEYSHIDDEN
;
722 value
= out
->KEYSHIDDEN_ANY
;
723 } else if (strcmp(name
, "keysexposed") == 0) {
724 mask
= out
->MASK_KEYSHIDDEN
;
725 value
= out
->KEYSHIDDEN_NO
;
726 } else if (strcmp(name
, "keyshidden") == 0) {
727 mask
= out
->MASK_KEYSHIDDEN
;
728 value
= out
->KEYSHIDDEN_YES
;
729 } else if (strcmp(name
, "keyssoft") == 0) {
730 mask
= out
->MASK_KEYSHIDDEN
;
731 value
= out
->KEYSHIDDEN_SOFT
;
735 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
742 bool AaptGroupEntry::getKeyboardName(const char* name
,
743 ResTable_config
* out
)
745 if (strcmp(name
, kWildcardName
) == 0) {
746 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
748 } else if (strcmp(name
, "nokeys") == 0) {
749 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
751 } else if (strcmp(name
, "qwerty") == 0) {
752 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
754 } else if (strcmp(name
, "12key") == 0) {
755 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
762 bool AaptGroupEntry::getNavigationName(const char* name
,
763 ResTable_config
* out
)
765 if (strcmp(name
, kWildcardName
) == 0) {
766 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
768 } else if (strcmp(name
, "nonav") == 0) {
769 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
771 } else if (strcmp(name
, "dpad") == 0) {
772 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
774 } else if (strcmp(name
, "trackball") == 0) {
775 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
777 } else if (strcmp(name
, "wheel") == 0) {
778 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
785 bool AaptGroupEntry::getScreenSizeName(const char* name
,
786 ResTable_config
* out
)
788 if (strcmp(name
, kWildcardName
) == 0) {
790 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
791 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
796 const char* x
= name
;
797 while (*x
>= '0' && *x
<= '9') x
++;
798 if (x
== name
|| *x
!= 'x') return false;
799 String8
xName(name
, x
-name
);
803 while (*y
>= '0' && *y
<= '9') y
++;
804 if (y
== name
|| *y
!= 0) return false;
805 String8
yName(x
, y
-x
);
807 uint16_t w
= (uint16_t)atoi(xName
.string());
808 uint16_t h
= (uint16_t)atoi(yName
.string());
814 out
->screenWidth
= w
;
815 out
->screenHeight
= h
;
821 bool AaptGroupEntry::getScreenLayoutName(const char* name
,
822 ResTable_config
* out
)
824 if (strcmp(name
, kWildcardName
) == 0) {
825 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_ANY
;
827 } else if (strcmp(name
, "smallscreen") == 0) {
828 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_SMALL
;
830 } else if (strcmp(name
, "normalscreen") == 0) {
831 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_NORMAL
;
833 } else if (strcmp(name
, "largescreen") == 0) {
834 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_LARGE
;
841 bool AaptGroupEntry::getVersionName(const char* name
,
842 ResTable_config
* out
)
844 if (strcmp(name
, kWildcardName
) == 0) {
846 out
->sdkVersion
= out
->SDKVERSION_ANY
;
847 out
->minorVersion
= out
->MINORVERSION_ANY
;
857 const char* s
= name
;
858 while (*s
>= '0' && *s
<= '9') s
++;
859 if (s
== name
|| *s
!= 0) return false;
860 String8
sdkName(name
, s
-name
);
863 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
864 out
->minorVersion
= 0;
870 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
872 int v
= mcc
.compare(o
.mcc
);
873 if (v
== 0) v
= mnc
.compare(o
.mnc
);
874 if (v
== 0) v
= locale
.compare(o
.locale
);
875 if (v
== 0) v
= vendor
.compare(o
.vendor
);
876 if (v
== 0) v
= orientation
.compare(o
.orientation
);
877 if (v
== 0) v
= density
.compare(o
.density
);
878 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
879 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
880 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
881 if (v
== 0) v
= navigation
.compare(o
.navigation
);
882 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
883 if (v
== 0) v
= screenLayout
.compare(o
.screenLayout
);
884 if (v
== 0) v
= version
.compare(o
.version
);
888 ResTable_config
AaptGroupEntry::toParams() const
890 ResTable_config params
;
891 memset(¶ms
, 0, sizeof(params
));
892 getMccName(mcc
.string(), ¶ms
);
893 getMncName(mnc
.string(), ¶ms
);
894 getLocaleName(locale
.string(), ¶ms
);
895 getOrientationName(orientation
.string(), ¶ms
);
896 getDensityName(density
.string(), ¶ms
);
897 getTouchscreenName(touchscreen
.string(), ¶ms
);
898 getKeysHiddenName(keysHidden
.string(), ¶ms
);
899 getKeyboardName(keyboard
.string(), ¶ms
);
900 getNavigationName(navigation
.string(), ¶ms
);
901 getScreenSizeName(screenSize
.string(), ¶ms
);
902 getScreenLayoutName(screenLayout
.string(), ¶ms
);
903 getVersionName(version
.string(), ¶ms
);
907 // =========================================================================
908 // =========================================================================
909 // =========================================================================
911 void* AaptFile::editData(size_t size
)
913 if (size
<= mBufferSize
) {
917 size_t allocSize
= (size
*3)/2;
918 void* buf
= realloc(mData
, allocSize
);
924 mBufferSize
= allocSize
;
928 void* AaptFile::editData(size_t* outSize
)
931 *outSize
= mDataSize
;
936 void* AaptFile::padData(size_t wordSize
)
938 const size_t extra
= mDataSize%wordSize
;
943 size_t initial
= mDataSize
;
944 void* data
= editData(initial
+(wordSize
-extra
));
946 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
951 status_t
AaptFile::writeData(const void* data
, size_t size
)
953 size_t end
= mDataSize
;
954 size_t total
= size
+ end
;
955 void* buf
= editData(total
);
957 return UNKNOWN_ERROR
;
959 memcpy(((char*)buf
)+end
, data
, size
);
963 void AaptFile::clearData()
965 if (mData
!= NULL
) free(mData
);
971 String8
AaptFile::getPrintableSource() const
974 String8
name(mGroupEntry
.locale
.string());
975 name
.appendPath(mGroupEntry
.vendor
.string());
976 name
.appendPath(mPath
);
977 name
.append(" #generated");
983 // =========================================================================
984 // =========================================================================
985 // =========================================================================
987 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
989 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
991 mFiles
.add(file
->getGroupEntry(), file
);
995 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
996 getPrintableSource().string());
997 return UNKNOWN_ERROR
;
1000 void AaptGroup::removeFile(size_t index
)
1002 mFiles
.removeItemsAt(index
);
1005 void AaptGroup::print() const
1007 printf(" %s\n", getPath().string());
1008 const size_t N
=mFiles
.size();
1010 for (i
=0; i
<N
; i
++) {
1011 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1012 const AaptGroupEntry
& e
= file
->getGroupEntry();
1013 if (file
->hasData()) {
1014 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
1015 (int)file
->getSize());
1017 printf(" Src: %s\n", file
->getPrintableSource().string());
1022 String8
AaptGroup::getPrintableSource() const
1024 if (mFiles
.size() > 0) {
1025 // Arbitrarily pull the first source file out of the list.
1026 return mFiles
.valueAt(0)->getPrintableSource();
1029 // Should never hit this case, but to be safe...
1034 // =========================================================================
1035 // =========================================================================
1036 // =========================================================================
1038 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1040 if (mFiles
.indexOfKey(name
) >= 0) {
1041 return ALREADY_EXISTS
;
1043 mFiles
.add(name
, file
);
1047 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1049 if (mDirs
.indexOfKey(name
) >= 0) {
1050 return ALREADY_EXISTS
;
1052 mDirs
.add(name
, dir
);
1056 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1059 String8 remain
= path
;
1061 sp
<AaptDir
> subdir
= this;
1062 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1063 subdir
= subdir
->makeDir(name
);
1066 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1068 return subdir
->mDirs
.valueAt(i
);
1070 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1071 subdir
->mDirs
.add(name
, dir
);
1075 void AaptDir::removeFile(const String8
& name
)
1077 mFiles
.removeItem(name
);
1080 void AaptDir::removeDir(const String8
& name
)
1082 mDirs
.removeItem(name
);
1085 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1087 sp
<AaptGroup
> origGroup
;
1089 // Find and remove the given file with shear, brute force!
1090 const size_t NG
= mFiles
.size();
1092 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1093 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1094 const size_t NF
= g
->getFiles().size();
1095 for (size_t j
=0; j
<NF
; j
++) {
1096 if (g
->getFiles().valueAt(j
) == file
) {
1100 mFiles
.removeItemsAt(i
);
1107 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1109 // Place the file under its new name.
1110 if (origGroup
!= NULL
) {
1111 return addLeafFile(newName
, file
);
1117 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1119 sp
<AaptGroup
> group
;
1120 if (mFiles
.indexOfKey(leafName
) >= 0) {
1121 group
= mFiles
.valueFor(leafName
);
1123 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1124 mFiles
.add(leafName
, group
);
1127 return group
->addFile(file
);
1130 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1131 const AaptGroupEntry
& kind
, const String8
& resType
)
1133 Vector
<String8
> fileNames
;
1138 dir
= opendir(srcDir
.string());
1140 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1141 return UNKNOWN_ERROR
;
1145 * Slurp the filenames out of the directory.
1148 struct dirent
* entry
;
1150 entry
= readdir(dir
);
1154 if (isHidden(srcDir
.string(), entry
->d_name
))
1157 fileNames
.add(String8(entry
->d_name
));
1166 * Stash away the files and recursively descend into subdirectories.
1168 const size_t N
= fileNames
.size();
1170 for (i
= 0; i
< N
; i
++) {
1171 String8
pathName(srcDir
);
1174 pathName
.appendPath(fileNames
[i
].string());
1175 type
= getFileType(pathName
.string());
1176 if (type
== kFileTypeDirectory
) {
1178 bool notAdded
= false;
1179 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1180 subdir
= mDirs
.valueFor(fileNames
[i
]);
1182 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1185 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1187 if (res
< NO_ERROR
) {
1190 if (res
> 0 && notAdded
) {
1191 mDirs
.add(fileNames
[i
], subdir
);
1194 } else if (type
== kFileTypeRegular
) {
1195 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1196 status_t err
= addLeafFile(fileNames
[i
], file
);
1197 if (err
!= NO_ERROR
) {
1204 if (bundle
->getVerbose())
1205 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1212 status_t
AaptDir::validate() const
1214 const size_t NF
= mFiles
.size();
1215 const size_t ND
= mDirs
.size();
1217 for (i
= 0; i
< NF
; i
++) {
1218 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1219 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1220 "Invalid filename. Unable to add.");
1221 return UNKNOWN_ERROR
;
1225 for (j
= i
+1; j
< NF
; j
++) {
1226 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1227 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1228 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1229 "File is case-insensitive equivalent to: %s",
1230 mFiles
.valueAt(j
)->getPrintableSource().string());
1231 return UNKNOWN_ERROR
;
1234 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1235 // (this is mostly caught by the "marked" stuff, below)
1238 for (j
= 0; j
< ND
; j
++) {
1239 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1240 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1241 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1242 "File conflicts with dir from: %s",
1243 mDirs
.valueAt(j
)->getPrintableSource().string());
1244 return UNKNOWN_ERROR
;
1249 for (i
= 0; i
< ND
; i
++) {
1250 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1251 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1252 "Invalid directory name, unable to add.");
1253 return UNKNOWN_ERROR
;
1257 for (j
= i
+1; j
< ND
; j
++) {
1258 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1259 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1260 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1261 "Directory is case-insensitive equivalent to: %s",
1262 mDirs
.valueAt(j
)->getPrintableSource().string());
1263 return UNKNOWN_ERROR
;
1267 status_t err
= mDirs
.valueAt(i
)->validate();
1268 if (err
!= NO_ERROR
) {
1276 void AaptDir::print() const
1278 const size_t ND
=getDirs().size();
1280 for (i
=0; i
<ND
; i
++) {
1281 getDirs().valueAt(i
)->print();
1284 const size_t NF
=getFiles().size();
1285 for (i
=0; i
<NF
; i
++) {
1286 getFiles().valueAt(i
)->print();
1290 String8
AaptDir::getPrintableSource() const
1292 if (mFiles
.size() > 0) {
1293 // Arbitrarily pull the first file out of the list as the source dir.
1294 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1296 if (mDirs
.size() > 0) {
1297 // Or arbitrarily pull the first dir out of the list as the source dir.
1298 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1301 // Should never hit this case, but to be safe...
1306 // =========================================================================
1307 // =========================================================================
1308 // =========================================================================
1310 sp
<AaptFile
> AaptAssets::addFile(
1311 const String8
& filePath
, const AaptGroupEntry
& entry
,
1312 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1313 const String8
& resType
)
1315 sp
<AaptDir
> dir
= this;
1316 sp
<AaptGroup
> group
;
1318 String8 root
, remain(filePath
), partialPath
;
1319 while (remain
.length() > 0) {
1320 root
= remain
.walkPath(&remain
);
1321 partialPath
.appendPath(root
);
1323 const String8
rootStr(root
);
1325 if (remain
.length() == 0) {
1326 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1328 group
= dir
->getFiles().valueAt(i
);
1330 group
= new AaptGroup(rootStr
, filePath
);
1331 status_t res
= dir
->addFile(rootStr
, group
);
1332 if (res
!= NO_ERROR
) {
1336 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1337 status_t res
= group
->addFile(file
);
1338 if (res
!= NO_ERROR
) {
1344 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1346 dir
= dir
->getDirs().valueAt(i
);
1348 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1349 status_t res
= dir
->addDir(rootStr
, subdir
);
1350 if (res
!= NO_ERROR
) {
1358 mGroupEntries
.add(entry
);
1359 if (outGroup
) *outGroup
= group
;
1363 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1364 const sp
<AaptFile
>& file
, const String8
& resType
)
1366 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1367 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1368 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1369 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1372 subdir
->addFile(leafName
, grr
);
1376 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1381 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1382 const size_t dirCount
=resDirs
.size();
1383 sp
<AaptAssets
> current
= this;
1385 const int N
= bundle
->getFileSpecCount();
1388 * If a package manifest was specified, include that first.
1390 if (bundle
->getAndroidManifestFile() != NULL
) {
1391 // place at root of zip.
1392 String8
srcFile(bundle
->getAndroidManifestFile());
1393 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1399 * If a directory of custom assets was supplied, slurp 'em up.
1401 if (bundle
->getAssetSourceDir()) {
1402 const char* assetDir
= bundle
->getAssetSourceDir();
1404 FileType type
= getFileType(assetDir
);
1405 if (type
== kFileTypeNonexistent
) {
1406 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1407 return UNKNOWN_ERROR
;
1409 if (type
!= kFileTypeDirectory
) {
1410 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1411 return UNKNOWN_ERROR
;
1414 String8
assetRoot(assetDir
);
1415 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1416 AaptGroupEntry group
;
1417 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1424 mGroupEntries
.add(group
);
1426 totalCount
+= count
;
1428 if (bundle
->getVerbose())
1429 printf("Found %d custom asset file%s in %s\n",
1430 count
, (count
==1) ? "" : "s", assetDir
);
1434 * If a directory of resource-specific assets was supplied, slurp 'em up.
1436 for (size_t i
=0; i
<dirCount
; i
++) {
1437 const char *res
= resDirs
[i
];
1439 type
= getFileType(res
);
1440 if (type
== kFileTypeNonexistent
) {
1441 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1442 return UNKNOWN_ERROR
;
1444 if (type
== kFileTypeDirectory
) {
1446 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1447 current
->setOverlay(nextOverlay
);
1448 current
= nextOverlay
;
1450 count
= current
->slurpResourceTree(bundle
, String8(res
));
1456 totalCount
+= count
;
1459 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1460 return UNKNOWN_ERROR
;
1466 * Now do any additional raw files.
1468 for (int arg
=0; arg
<N
; arg
++) {
1469 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1471 FileType type
= getFileType(assetDir
);
1472 if (type
== kFileTypeNonexistent
) {
1473 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1474 return UNKNOWN_ERROR
;
1476 if (type
!= kFileTypeDirectory
) {
1477 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1478 return UNKNOWN_ERROR
;
1481 String8
assetRoot(assetDir
);
1483 if (bundle
->getVerbose())
1484 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1487 * Do a recursive traversal of subdir tree. We don't make any
1488 * guarantees about ordering, so we're okay with an inorder search
1489 * using whatever order the OS happens to hand back to us.
1491 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1493 /* failure; report error and remove archive */
1497 totalCount
+= count
;
1499 if (bundle
->getVerbose())
1500 printf("Found %d asset file%s in %s\n",
1501 count
, (count
==1) ? "" : "s", assetDir
);
1505 if (count
!= NO_ERROR
) {
1515 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1516 const AaptGroupEntry
& kind
,
1517 const String8
& resType
)
1519 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1521 mGroupEntries
.add(kind
);
1527 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1531 DIR* dir
= opendir(srcDir
.string());
1533 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1534 return UNKNOWN_ERROR
;
1540 * Run through the directory, looking for dirs that match the
1544 struct dirent
* entry
= readdir(dir
);
1545 if (entry
== NULL
) {
1549 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1553 String8
subdirName(srcDir
);
1554 subdirName
.appendPath(entry
->d_name
);
1556 AaptGroupEntry group
;
1558 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1560 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1566 FileType type
= getFileType(subdirName
.string());
1568 if (type
== kFileTypeDirectory
) {
1569 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1570 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1577 mGroupEntries
.add(group
);
1583 if (bundle
->getVerbose()) {
1584 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1600 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1603 SortedVector
<AaptGroupEntry
> entries
;
1605 ZipFile
* zip
= new ZipFile
;
1606 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1607 if (err
!= NO_ERROR
) {
1608 fprintf(stderr
, "error opening zip file %s\n", filename
);
1614 const int N
= zip
->getNumEntries();
1615 for (int i
=0; i
<N
; i
++) {
1616 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1617 if (entry
->getDeleted()) {
1621 String8
entryName(entry
->getFileName());
1623 String8 dirName
= entryName
.getPathDir();
1624 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1627 AaptGroupEntry kind
;
1630 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1631 // these are the resources, pull their type out of the directory name
1632 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1634 // these are untyped and don't have an AaptGroupEntry
1636 if (entries
.indexOf(kind
) < 0) {
1638 mGroupEntries
.add(kind
);
1641 // use the one from the zip file if they both exist.
1642 dir
->removeFile(entryName
.getPathLeaf());
1644 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1645 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1646 if (err
!= NO_ERROR
) {
1647 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1651 file
->setCompressionMethod(entry
->getCompressionMethod());
1654 if (entryName
== "AndroidManifest.xml") {
1655 printf("AndroidManifest.xml\n");
1657 printf("\n\nfile: %s\n", entryName
.string());
1660 size_t len
= entry
->getUncompressedLen();
1661 void* data
= zip
->uncompress(entry
);
1662 void* buf
= file
->editData(len
);
1663 memcpy(buf
, data
, len
);
1667 const unsigned char* p
= (unsigned char*)data
;
1668 const unsigned char* end
= p
+len
;
1670 for (int i
=0; i
<32 && p
< end
; i
++) {
1671 printf("0x%03x ", i
*0x10 + OFF
);
1672 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1673 printf(" %02x", *p
);
1690 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1692 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1694 sym
= new AaptSymbols();
1695 mSymbols
.add(name
, sym
);
1700 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1702 if (!mHaveIncludedAssets
) {
1703 // Add in all includes.
1704 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1705 const size_t N
=incl
.size();
1706 for (size_t i
=0; i
<N
; i
++) {
1707 if (bundle
->getVerbose())
1708 printf("Including resources from package: %s\n", incl
[i
]);
1709 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1710 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1712 return UNKNOWN_ERROR
;
1715 mHaveIncludedAssets
= true;
1721 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1723 const ResTable
& res
= getIncludedResources();
1725 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1728 const ResTable
& AaptAssets::getIncludedResources() const
1730 return mIncludedAssets
.getResources(false);
1733 void AaptAssets::print() const
1735 printf("Locale/Vendor pairs:\n");
1736 const size_t N
=mGroupEntries
.size();
1737 for (size_t i
=0; i
<N
; i
++) {
1739 mGroupEntries
.itemAt(i
).locale
.string(),
1740 mGroupEntries
.itemAt(i
).vendor
.string());
1743 printf("\nFiles:\n");
1748 valid_symbol_name(const String8
& symbol
)
1750 static char const * const KEYWORDS
[] = {
1751 "abstract", "assert", "boolean", "break",
1752 "byte", "case", "catch", "char", "class", "const", "continue",
1753 "default", "do", "double", "else", "enum", "extends", "final",
1754 "finally", "float", "for", "goto", "if", "implements", "import",
1755 "instanceof", "int", "interface", "long", "native", "new", "package",
1756 "private", "protected", "public", "return", "short", "static",
1757 "strictfp", "super", "switch", "synchronized", "this", "throw",
1758 "throws", "transient", "try", "void", "volatile", "while",
1759 "true", "false", "null",
1762 const char*const* k
= KEYWORDS
;
1763 const char*const s
= symbol
.string();
1765 if (0 == strcmp(s
, *k
)) {