]>
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
= 0;
660 char* c
= (char*)name
;
661 while (*c
>= '0' && *c
<= '9') {
665 // check that we have 'dpi' after the last digit.
666 if (toupper(c
[0]) != 'D' ||
667 toupper(c
[1]) != 'P' ||
668 toupper(c
[2]) != 'I' ||
673 // temporarily replace the first letter with \0 to
682 if (out
) out
->density
= d
;
689 bool AaptGroupEntry::getTouchscreenName(const char* name
,
690 ResTable_config
* out
)
692 if (strcmp(name
, kWildcardName
) == 0) {
693 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
695 } else if (strcmp(name
, "notouch") == 0) {
696 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
698 } else if (strcmp(name
, "stylus") == 0) {
699 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
701 } else if (strcmp(name
, "finger") == 0) {
702 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
709 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
710 ResTable_config
* out
)
714 if (strcmp(name
, kWildcardName
) == 0) {
715 mask
= out
->MASK_KEYSHIDDEN
;
716 value
= out
->KEYSHIDDEN_ANY
;
717 } else if (strcmp(name
, "keysexposed") == 0) {
718 mask
= out
->MASK_KEYSHIDDEN
;
719 value
= out
->KEYSHIDDEN_NO
;
720 } else if (strcmp(name
, "keyshidden") == 0) {
721 mask
= out
->MASK_KEYSHIDDEN
;
722 value
= out
->KEYSHIDDEN_YES
;
723 } else if (strcmp(name
, "keyssoft") == 0) {
724 mask
= out
->MASK_KEYSHIDDEN
;
725 value
= out
->KEYSHIDDEN_SOFT
;
729 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
736 bool AaptGroupEntry::getKeyboardName(const char* name
,
737 ResTable_config
* out
)
739 if (strcmp(name
, kWildcardName
) == 0) {
740 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
742 } else if (strcmp(name
, "nokeys") == 0) {
743 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
745 } else if (strcmp(name
, "qwerty") == 0) {
746 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
748 } else if (strcmp(name
, "12key") == 0) {
749 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
756 bool AaptGroupEntry::getNavigationName(const char* name
,
757 ResTable_config
* out
)
759 if (strcmp(name
, kWildcardName
) == 0) {
760 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
762 } else if (strcmp(name
, "nonav") == 0) {
763 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
765 } else if (strcmp(name
, "dpad") == 0) {
766 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
768 } else if (strcmp(name
, "trackball") == 0) {
769 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
771 } else if (strcmp(name
, "wheel") == 0) {
772 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
779 bool AaptGroupEntry::getScreenSizeName(const char* name
,
780 ResTable_config
* out
)
782 if (strcmp(name
, kWildcardName
) == 0) {
784 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
785 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
790 const char* x
= name
;
791 while (*x
>= '0' && *x
<= '9') x
++;
792 if (x
== name
|| *x
!= 'x') return false;
793 String8
xName(name
, x
-name
);
797 while (*y
>= '0' && *y
<= '9') y
++;
798 if (y
== name
|| *y
!= 0) return false;
799 String8
yName(x
, y
-x
);
801 uint16_t w
= (uint16_t)atoi(xName
.string());
802 uint16_t h
= (uint16_t)atoi(yName
.string());
808 out
->screenWidth
= w
;
809 out
->screenHeight
= h
;
815 bool AaptGroupEntry::getScreenLayoutName(const char* name
,
816 ResTable_config
* out
)
818 if (strcmp(name
, kWildcardName
) == 0) {
819 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_ANY
;
821 } else if (strcmp(name
, "smallscreen") == 0) {
822 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_SMALL
;
824 } else if (strcmp(name
, "normalscreen") == 0) {
825 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_NORMAL
;
827 } else if (strcmp(name
, "largescreen") == 0) {
828 if (out
) out
->screenLayout
= out
->SCREENLAYOUT_LARGE
;
835 bool AaptGroupEntry::getVersionName(const char* name
,
836 ResTable_config
* out
)
838 if (strcmp(name
, kWildcardName
) == 0) {
840 out
->sdkVersion
= out
->SDKVERSION_ANY
;
841 out
->minorVersion
= out
->MINORVERSION_ANY
;
851 const char* s
= name
;
852 while (*s
>= '0' && *s
<= '9') s
++;
853 if (s
== name
|| *s
!= 0) return false;
854 String8
sdkName(name
, s
-name
);
857 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
858 out
->minorVersion
= 0;
864 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
866 int v
= mcc
.compare(o
.mcc
);
867 if (v
== 0) v
= mnc
.compare(o
.mnc
);
868 if (v
== 0) v
= locale
.compare(o
.locale
);
869 if (v
== 0) v
= vendor
.compare(o
.vendor
);
870 if (v
== 0) v
= orientation
.compare(o
.orientation
);
871 if (v
== 0) v
= density
.compare(o
.density
);
872 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
873 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
874 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
875 if (v
== 0) v
= navigation
.compare(o
.navigation
);
876 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
877 if (v
== 0) v
= screenLayout
.compare(o
.screenLayout
);
878 if (v
== 0) v
= version
.compare(o
.version
);
882 ResTable_config
AaptGroupEntry::toParams() const
884 ResTable_config params
;
885 memset(¶ms
, 0, sizeof(params
));
886 getMccName(mcc
.string(), ¶ms
);
887 getMncName(mnc
.string(), ¶ms
);
888 getLocaleName(locale
.string(), ¶ms
);
889 getOrientationName(orientation
.string(), ¶ms
);
890 getDensityName(density
.string(), ¶ms
);
891 getTouchscreenName(touchscreen
.string(), ¶ms
);
892 getKeysHiddenName(keysHidden
.string(), ¶ms
);
893 getKeyboardName(keyboard
.string(), ¶ms
);
894 getNavigationName(navigation
.string(), ¶ms
);
895 getScreenSizeName(screenSize
.string(), ¶ms
);
896 getScreenLayoutName(screenLayout
.string(), ¶ms
);
897 getVersionName(version
.string(), ¶ms
);
901 // =========================================================================
902 // =========================================================================
903 // =========================================================================
905 void* AaptFile::editData(size_t size
)
907 if (size
<= mBufferSize
) {
911 size_t allocSize
= (size
*3)/2;
912 void* buf
= realloc(mData
, allocSize
);
918 mBufferSize
= allocSize
;
922 void* AaptFile::editData(size_t* outSize
)
925 *outSize
= mDataSize
;
930 void* AaptFile::padData(size_t wordSize
)
932 const size_t extra
= mDataSize%wordSize
;
937 size_t initial
= mDataSize
;
938 void* data
= editData(initial
+(wordSize
-extra
));
940 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
945 status_t
AaptFile::writeData(const void* data
, size_t size
)
947 size_t end
= mDataSize
;
948 size_t total
= size
+ end
;
949 void* buf
= editData(total
);
951 return UNKNOWN_ERROR
;
953 memcpy(((char*)buf
)+end
, data
, size
);
957 void AaptFile::clearData()
959 if (mData
!= NULL
) free(mData
);
965 String8
AaptFile::getPrintableSource() const
968 String8
name(mGroupEntry
.locale
.string());
969 name
.appendPath(mGroupEntry
.vendor
.string());
970 name
.appendPath(mPath
);
971 name
.append(" #generated");
977 // =========================================================================
978 // =========================================================================
979 // =========================================================================
981 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
983 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
985 mFiles
.add(file
->getGroupEntry(), file
);
989 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
990 getPrintableSource().string());
991 return UNKNOWN_ERROR
;
994 void AaptGroup::removeFile(size_t index
)
996 mFiles
.removeItemsAt(index
);
999 void AaptGroup::print() const
1001 printf(" %s\n", getPath().string());
1002 const size_t N
=mFiles
.size();
1004 for (i
=0; i
<N
; i
++) {
1005 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1006 const AaptGroupEntry
& e
= file
->getGroupEntry();
1007 if (file
->hasData()) {
1008 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
1009 (int)file
->getSize());
1011 printf(" Src: %s\n", file
->getPrintableSource().string());
1016 String8
AaptGroup::getPrintableSource() const
1018 if (mFiles
.size() > 0) {
1019 // Arbitrarily pull the first source file out of the list.
1020 return mFiles
.valueAt(0)->getPrintableSource();
1023 // Should never hit this case, but to be safe...
1028 // =========================================================================
1029 // =========================================================================
1030 // =========================================================================
1032 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1034 if (mFiles
.indexOfKey(name
) >= 0) {
1035 return ALREADY_EXISTS
;
1037 mFiles
.add(name
, file
);
1041 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1043 if (mDirs
.indexOfKey(name
) >= 0) {
1044 return ALREADY_EXISTS
;
1046 mDirs
.add(name
, dir
);
1050 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1053 String8 remain
= path
;
1055 sp
<AaptDir
> subdir
= this;
1056 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1057 subdir
= subdir
->makeDir(name
);
1060 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1062 return subdir
->mDirs
.valueAt(i
);
1064 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1065 subdir
->mDirs
.add(name
, dir
);
1069 void AaptDir::removeFile(const String8
& name
)
1071 mFiles
.removeItem(name
);
1074 void AaptDir::removeDir(const String8
& name
)
1076 mDirs
.removeItem(name
);
1079 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1081 sp
<AaptGroup
> origGroup
;
1083 // Find and remove the given file with shear, brute force!
1084 const size_t NG
= mFiles
.size();
1086 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1087 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1088 const size_t NF
= g
->getFiles().size();
1089 for (size_t j
=0; j
<NF
; j
++) {
1090 if (g
->getFiles().valueAt(j
) == file
) {
1094 mFiles
.removeItemsAt(i
);
1101 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1103 // Place the file under its new name.
1104 if (origGroup
!= NULL
) {
1105 return addLeafFile(newName
, file
);
1111 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1113 sp
<AaptGroup
> group
;
1114 if (mFiles
.indexOfKey(leafName
) >= 0) {
1115 group
= mFiles
.valueFor(leafName
);
1117 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1118 mFiles
.add(leafName
, group
);
1121 return group
->addFile(file
);
1124 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1125 const AaptGroupEntry
& kind
, const String8
& resType
)
1127 Vector
<String8
> fileNames
;
1132 dir
= opendir(srcDir
.string());
1134 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1135 return UNKNOWN_ERROR
;
1139 * Slurp the filenames out of the directory.
1142 struct dirent
* entry
;
1144 entry
= readdir(dir
);
1148 if (isHidden(srcDir
.string(), entry
->d_name
))
1151 fileNames
.add(String8(entry
->d_name
));
1160 * Stash away the files and recursively descend into subdirectories.
1162 const size_t N
= fileNames
.size();
1164 for (i
= 0; i
< N
; i
++) {
1165 String8
pathName(srcDir
);
1168 pathName
.appendPath(fileNames
[i
].string());
1169 type
= getFileType(pathName
.string());
1170 if (type
== kFileTypeDirectory
) {
1172 bool notAdded
= false;
1173 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1174 subdir
= mDirs
.valueFor(fileNames
[i
]);
1176 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1179 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1181 if (res
< NO_ERROR
) {
1184 if (res
> 0 && notAdded
) {
1185 mDirs
.add(fileNames
[i
], subdir
);
1188 } else if (type
== kFileTypeRegular
) {
1189 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1190 status_t err
= addLeafFile(fileNames
[i
], file
);
1191 if (err
!= NO_ERROR
) {
1198 if (bundle
->getVerbose())
1199 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1206 status_t
AaptDir::validate() const
1208 const size_t NF
= mFiles
.size();
1209 const size_t ND
= mDirs
.size();
1211 for (i
= 0; i
< NF
; i
++) {
1212 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1213 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1214 "Invalid filename. Unable to add.");
1215 return UNKNOWN_ERROR
;
1219 for (j
= i
+1; j
< NF
; j
++) {
1220 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1221 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1222 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1223 "File is case-insensitive equivalent to: %s",
1224 mFiles
.valueAt(j
)->getPrintableSource().string());
1225 return UNKNOWN_ERROR
;
1228 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1229 // (this is mostly caught by the "marked" stuff, below)
1232 for (j
= 0; j
< ND
; j
++) {
1233 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1234 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1235 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1236 "File conflicts with dir from: %s",
1237 mDirs
.valueAt(j
)->getPrintableSource().string());
1238 return UNKNOWN_ERROR
;
1243 for (i
= 0; i
< ND
; i
++) {
1244 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1245 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1246 "Invalid directory name, unable to add.");
1247 return UNKNOWN_ERROR
;
1251 for (j
= i
+1; j
< ND
; j
++) {
1252 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1253 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1254 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1255 "Directory is case-insensitive equivalent to: %s",
1256 mDirs
.valueAt(j
)->getPrintableSource().string());
1257 return UNKNOWN_ERROR
;
1261 status_t err
= mDirs
.valueAt(i
)->validate();
1262 if (err
!= NO_ERROR
) {
1270 void AaptDir::print() const
1272 const size_t ND
=getDirs().size();
1274 for (i
=0; i
<ND
; i
++) {
1275 getDirs().valueAt(i
)->print();
1278 const size_t NF
=getFiles().size();
1279 for (i
=0; i
<NF
; i
++) {
1280 getFiles().valueAt(i
)->print();
1284 String8
AaptDir::getPrintableSource() const
1286 if (mFiles
.size() > 0) {
1287 // Arbitrarily pull the first file out of the list as the source dir.
1288 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1290 if (mDirs
.size() > 0) {
1291 // Or arbitrarily pull the first dir out of the list as the source dir.
1292 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1295 // Should never hit this case, but to be safe...
1300 // =========================================================================
1301 // =========================================================================
1302 // =========================================================================
1304 sp
<AaptFile
> AaptAssets::addFile(
1305 const String8
& filePath
, const AaptGroupEntry
& entry
,
1306 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1307 const String8
& resType
)
1309 sp
<AaptDir
> dir
= this;
1310 sp
<AaptGroup
> group
;
1312 String8 root
, remain(filePath
), partialPath
;
1313 while (remain
.length() > 0) {
1314 root
= remain
.walkPath(&remain
);
1315 partialPath
.appendPath(root
);
1317 const String8
rootStr(root
);
1319 if (remain
.length() == 0) {
1320 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1322 group
= dir
->getFiles().valueAt(i
);
1324 group
= new AaptGroup(rootStr
, filePath
);
1325 status_t res
= dir
->addFile(rootStr
, group
);
1326 if (res
!= NO_ERROR
) {
1330 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1331 status_t res
= group
->addFile(file
);
1332 if (res
!= NO_ERROR
) {
1338 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1340 dir
= dir
->getDirs().valueAt(i
);
1342 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1343 status_t res
= dir
->addDir(rootStr
, subdir
);
1344 if (res
!= NO_ERROR
) {
1352 mGroupEntries
.add(entry
);
1353 if (outGroup
) *outGroup
= group
;
1357 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1358 const sp
<AaptFile
>& file
, const String8
& resType
)
1360 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1361 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1362 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1363 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1366 subdir
->addFile(leafName
, grr
);
1370 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1375 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1376 const size_t dirCount
=resDirs
.size();
1377 sp
<AaptAssets
> current
= this;
1379 const int N
= bundle
->getFileSpecCount();
1382 * If a package manifest was specified, include that first.
1384 if (bundle
->getAndroidManifestFile() != NULL
) {
1385 // place at root of zip.
1386 String8
srcFile(bundle
->getAndroidManifestFile());
1387 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1393 * If a directory of custom assets was supplied, slurp 'em up.
1395 if (bundle
->getAssetSourceDir()) {
1396 const char* assetDir
= bundle
->getAssetSourceDir();
1398 FileType type
= getFileType(assetDir
);
1399 if (type
== kFileTypeNonexistent
) {
1400 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1401 return UNKNOWN_ERROR
;
1403 if (type
!= kFileTypeDirectory
) {
1404 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1405 return UNKNOWN_ERROR
;
1408 String8
assetRoot(assetDir
);
1409 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1410 AaptGroupEntry group
;
1411 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1418 mGroupEntries
.add(group
);
1420 totalCount
+= count
;
1422 if (bundle
->getVerbose())
1423 printf("Found %d custom asset file%s in %s\n",
1424 count
, (count
==1) ? "" : "s", assetDir
);
1428 * If a directory of resource-specific assets was supplied, slurp 'em up.
1430 for (size_t i
=0; i
<dirCount
; i
++) {
1431 const char *res
= resDirs
[i
];
1433 type
= getFileType(res
);
1434 if (type
== kFileTypeNonexistent
) {
1435 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1436 return UNKNOWN_ERROR
;
1438 if (type
== kFileTypeDirectory
) {
1440 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1441 current
->setOverlay(nextOverlay
);
1442 current
= nextOverlay
;
1444 count
= current
->slurpResourceTree(bundle
, String8(res
));
1450 totalCount
+= count
;
1453 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1454 return UNKNOWN_ERROR
;
1460 * Now do any additional raw files.
1462 for (int arg
=0; arg
<N
; arg
++) {
1463 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1465 FileType type
= getFileType(assetDir
);
1466 if (type
== kFileTypeNonexistent
) {
1467 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1468 return UNKNOWN_ERROR
;
1470 if (type
!= kFileTypeDirectory
) {
1471 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1472 return UNKNOWN_ERROR
;
1475 String8
assetRoot(assetDir
);
1477 if (bundle
->getVerbose())
1478 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1481 * Do a recursive traversal of subdir tree. We don't make any
1482 * guarantees about ordering, so we're okay with an inorder search
1483 * using whatever order the OS happens to hand back to us.
1485 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1487 /* failure; report error and remove archive */
1491 totalCount
+= count
;
1493 if (bundle
->getVerbose())
1494 printf("Found %d asset file%s in %s\n",
1495 count
, (count
==1) ? "" : "s", assetDir
);
1499 if (count
!= NO_ERROR
) {
1509 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1510 const AaptGroupEntry
& kind
,
1511 const String8
& resType
)
1513 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1515 mGroupEntries
.add(kind
);
1521 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1525 DIR* dir
= opendir(srcDir
.string());
1527 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1528 return UNKNOWN_ERROR
;
1534 * Run through the directory, looking for dirs that match the
1538 struct dirent
* entry
= readdir(dir
);
1539 if (entry
== NULL
) {
1543 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1547 String8
subdirName(srcDir
);
1548 subdirName
.appendPath(entry
->d_name
);
1550 AaptGroupEntry group
;
1552 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1554 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1560 FileType type
= getFileType(subdirName
.string());
1562 if (type
== kFileTypeDirectory
) {
1563 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1564 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1571 mGroupEntries
.add(group
);
1577 if (bundle
->getVerbose()) {
1578 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1594 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1597 SortedVector
<AaptGroupEntry
> entries
;
1599 ZipFile
* zip
= new ZipFile
;
1600 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1601 if (err
!= NO_ERROR
) {
1602 fprintf(stderr
, "error opening zip file %s\n", filename
);
1608 const int N
= zip
->getNumEntries();
1609 for (int i
=0; i
<N
; i
++) {
1610 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1611 if (entry
->getDeleted()) {
1615 String8
entryName(entry
->getFileName());
1617 String8 dirName
= entryName
.getPathDir();
1618 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1621 AaptGroupEntry kind
;
1624 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1625 // these are the resources, pull their type out of the directory name
1626 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1628 // these are untyped and don't have an AaptGroupEntry
1630 if (entries
.indexOf(kind
) < 0) {
1632 mGroupEntries
.add(kind
);
1635 // use the one from the zip file if they both exist.
1636 dir
->removeFile(entryName
.getPathLeaf());
1638 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1639 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1640 if (err
!= NO_ERROR
) {
1641 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1645 file
->setCompressionMethod(entry
->getCompressionMethod());
1648 if (entryName
== "AndroidManifest.xml") {
1649 printf("AndroidManifest.xml\n");
1651 printf("\n\nfile: %s\n", entryName
.string());
1654 size_t len
= entry
->getUncompressedLen();
1655 void* data
= zip
->uncompress(entry
);
1656 void* buf
= file
->editData(len
);
1657 memcpy(buf
, data
, len
);
1661 const unsigned char* p
= (unsigned char*)data
;
1662 const unsigned char* end
= p
+len
;
1664 for (int i
=0; i
<32 && p
< end
; i
++) {
1665 printf("0x%03x ", i
*0x10 + OFF
);
1666 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1667 printf(" %02x", *p
);
1684 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1686 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1688 sym
= new AaptSymbols();
1689 mSymbols
.add(name
, sym
);
1694 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1696 if (!mHaveIncludedAssets
) {
1697 // Add in all includes.
1698 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1699 const size_t N
=incl
.size();
1700 for (size_t i
=0; i
<N
; i
++) {
1701 if (bundle
->getVerbose())
1702 printf("Including resources from package: %s\n", incl
[i
]);
1703 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1704 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1706 return UNKNOWN_ERROR
;
1709 mHaveIncludedAssets
= true;
1715 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1717 const ResTable
& res
= getIncludedResources();
1719 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1722 const ResTable
& AaptAssets::getIncludedResources() const
1724 return mIncludedAssets
.getResources(false);
1727 void AaptAssets::print() const
1729 printf("Locale/Vendor pairs:\n");
1730 const size_t N
=mGroupEntries
.size();
1731 for (size_t i
=0; i
<N
; i
++) {
1733 mGroupEntries
.itemAt(i
).locale
.string(),
1734 mGroupEntries
.itemAt(i
).vendor
.string());
1737 printf("\nFiles:\n");
1742 valid_symbol_name(const String8
& symbol
)
1744 static char const * const KEYWORDS
[] = {
1745 "abstract", "assert", "boolean", "break",
1746 "byte", "case", "catch", "char", "class", "const", "continue",
1747 "default", "do", "double", "else", "enum", "extends", "final",
1748 "finally", "float", "for", "goto", "if", "implements", "import",
1749 "instanceof", "int", "interface", "long", "native", "new", "package",
1750 "private", "protected", "public", "return", "short", "static",
1751 "strictfp", "super", "switch", "synchronized", "this", "throw",
1752 "throws", "transient", "try", "void", "volatile", "while",
1753 "true", "false", "null",
1756 const char*const* k
= KEYWORDS
;
1757 const char*const s
= symbol
.string();
1759 if (0 == strcmp(s
, *k
)) {