]>
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 char* kExcludeExtension
= ".EXCLUDE";
21 static const size_t kMaxAssetFileName
= 100;
23 static const String8
kResString(kResourceDir
);
26 * Names of asset files must meet the following criteria:
28 * - the filename length must be less than kMaxAssetFileName bytes long
29 * (and can't be empty)
30 * - all characters must be 7-bit printable ASCII
31 * - none of { '/' '\\' ':' }
33 * Pass in just the filename, not the full path.
35 static bool validateFileName(const char* fileName
)
37 const char* cp
= fileName
;
41 if ((*cp
& 0x80) != 0)
42 return false; // reject high ASCII
43 if (*cp
< 0x20 || *cp
>= 0x7f)
44 return false; // reject control chars and 0x7f
45 if (strchr(kInvalidChars
, *cp
) != NULL
)
46 return false; // reject path sep chars
51 if (len
< 1 || len
> kMaxAssetFileName
)
52 return false; // reject empty or too long
57 static bool isHidden(const char *root
, const char *path
)
59 const char *type
= NULL
;
61 // Skip all hidden files.
63 // Skip ., .. and .svn but don't chatter about it.
64 if (strcmp(path
, ".") == 0
65 || strcmp(path
, "..") == 0
66 || strcmp(path
, ".svn") == 0) {
70 } else if (path
[0] == '_') {
71 // skip directories starting with _ (don't chatter about it)
72 String8
subdirName(root
);
73 subdirName
.appendPath(path
);
74 if (getFileType(subdirName
.string()) == kFileTypeDirectory
) {
77 } else if (strcmp(path
, "CVS") == 0) {
78 // Skip CVS but don't chatter about it.
80 } else if (strcasecmp(path
, "thumbs.db") == 0
81 || strcasecmp(path
, "picasa.ini") == 0) {
82 // Skip suspected image indexes files.
84 } else if (path
[strlen(path
)-1] == '~') {
85 // Skip suspected emacs backup files.
88 // Let everything else through.
92 /* If we get this far, "type" should be set and the file
95 String8
subdirName(root
);
96 subdirName
.appendPath(path
);
97 fprintf(stderr
, " (skipping %s %s '%s')\n", type
,
98 getFileType(subdirName
.string())==kFileTypeDirectory
? "dir":"file",
104 // =========================================================================
105 // =========================================================================
106 // =========================================================================
109 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
)
111 ResTable_config config
;
114 if (getMccName(part
.string(), &config
)) {
121 if (getMncName(part
.string(), &config
)) {
128 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
129 *axis
= AXIS_LANGUAGE
;
130 *value
= part
[1] << 8 | part
[0];
134 // locale - language_REGION
135 if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1])
136 && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) {
137 *axis
= AXIS_LANGUAGE
;
138 *value
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]);
143 if (getOrientationName(part
.string(), &config
)) {
144 *axis
= AXIS_ORIENTATION
;
145 *value
= config
.orientation
;
150 if (getDensityName(part
.string(), &config
)) {
151 *axis
= AXIS_DENSITY
;
152 *value
= config
.density
;
157 if (getTouchscreenName(part
.string(), &config
)) {
158 *axis
= AXIS_TOUCHSCREEN
;
159 *value
= config
.touchscreen
;
164 if (getKeysHiddenName(part
.string(), &config
)) {
165 *axis
= AXIS_KEYSHIDDEN
;
166 *value
= config
.inputFlags
;
171 if (getKeyboardName(part
.string(), &config
)) {
172 *axis
= AXIS_KEYBOARD
;
173 *value
= config
.keyboard
;
178 if (getNavigationName(part
.string(), &config
)) {
179 *axis
= AXIS_NAVIGATION
;
180 *value
= config
.navigation
;
185 if (getScreenSizeName(part
.string(), &config
)) {
186 *axis
= AXIS_SCREENSIZE
;
187 *value
= config
.screenSize
;
192 if (getVersionName(part
.string(), &config
)) {
193 *axis
= AXIS_VERSION
;
194 *value
= config
.version
;
202 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
204 Vector
<String8
> parts
;
206 String8 mcc
, mnc
, loc
, orient
, den
, touch
, key
, keysHidden
, nav
, size
, vers
;
210 while (NULL
!= (q
= strchr(p
, '-'))) {
214 //printf("part: %s\n", parts[parts.size()-1].string());
220 //printf("part: %s\n", parts[parts.size()-1].string());
222 const int N
= parts
.size();
224 String8 part
= parts
[index
];
227 if (!isValidResourceType(part
)) {
239 if (getMccName(part
.string())) {
248 //printf("not mcc: %s\n", part.string());
252 if (getMncName(part
.string())) {
261 //printf("not mcc: %s\n", part.string());
265 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
274 //printf("not language: %s\n", part.string());
279 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
282 loc
+= part
.string() + 1;
290 //printf("not region: %s\n", part.string());
294 if (getOrientationName(part
.string())) {
303 //printf("not orientation: %s\n", part.string());
307 if (getDensityName(part
.string())) {
316 //printf("not density: %s\n", part.string());
320 if (getTouchscreenName(part
.string())) {
329 //printf("not touchscreen: %s\n", part.string());
333 if (getKeysHiddenName(part
.string())) {
342 //printf("not keysHidden: %s\n", part.string());
346 if (getKeyboardName(part
.string())) {
355 //printf("not keyboard: %s\n", part.string());
358 if (getNavigationName(part
.string())) {
367 //printf("not navigation: %s\n", part.string());
370 if (getScreenSizeName(part
.string())) {
379 //printf("not screen size: %s\n", part.string());
382 if (getVersionName(part
.string())) {
391 //printf("not version: %s\n", part.string());
394 // if there are extra parts, it doesn't match
401 this->orientation
= orient
;
403 this->touchscreen
= touch
;
404 this->keysHidden
= keysHidden
;
405 this->keyboard
= key
;
406 this->navigation
= nav
;
407 this->screenSize
= size
;
408 this->version
= vers
;
410 // what is this anyway?
417 AaptGroupEntry::toString() const
419 String8 s
= this->mcc
;
425 s
+= this->orientation
;
444 AaptGroupEntry::toDirName(const String8
& resType
) const
447 if (this->mcc
!= "") {
451 if (this->mnc
!= "") {
455 if (this->locale
!= "") {
459 if (this->orientation
!= "") {
463 if (this->density
!= "") {
467 if (this->touchscreen
!= "") {
471 if (this->keysHidden
!= "") {
475 if (this->keyboard
!= "") {
479 if (this->navigation
!= "") {
483 if (this->screenSize
!= "") {
487 if (this->version
!= "") {
495 bool AaptGroupEntry::getMccName(const char* name
,
496 ResTable_config
* out
)
498 if (strcmp(name
, kWildcardName
) == 0) {
499 if (out
) out
->mcc
= 0;
502 const char* c
= name
;
503 if (tolower(*c
) != 'm') return false;
505 if (tolower(*c
) != 'c') return false;
507 if (tolower(*c
) != 'c') return false;
512 while (*c
>= '0' && *c
<= '9') {
515 if (*c
!= 0) return false;
516 if (c
-val
!= 3) return false;
520 if (out
) out
->mcc
= d
;
527 bool AaptGroupEntry::getMncName(const char* name
,
528 ResTable_config
* out
)
530 if (strcmp(name
, kWildcardName
) == 0) {
531 if (out
) out
->mcc
= 0;
534 const char* c
= name
;
535 if (tolower(*c
) != 'm') return false;
537 if (tolower(*c
) != 'n') return false;
539 if (tolower(*c
) != 'c') return false;
544 while (*c
>= '0' && *c
<= '9') {
547 if (*c
!= 0) return false;
548 if (c
-val
== 0 || c
-val
> 3) return false;
552 if (out
) out
->mnc
= d
;
560 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
563 * TODO: Should insist that the first two letters are lower case, and the
564 * second two are upper.
566 bool AaptGroupEntry::getLocaleName(const char* fileName
,
567 ResTable_config
* out
)
569 if (strcmp(fileName
, kWildcardName
) == 0
570 || strcmp(fileName
, kDefaultLocale
) == 0) {
572 out
->language
[0] = 0;
573 out
->language
[1] = 0;
580 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
582 out
->language
[0] = fileName
[0];
583 out
->language
[1] = fileName
[1];
590 if (strlen(fileName
) == 5 &&
591 isalpha(fileName
[0]) &&
592 isalpha(fileName
[1]) &&
593 fileName
[2] == '-' &&
594 isalpha(fileName
[3]) &&
595 isalpha(fileName
[4])) {
597 out
->language
[0] = fileName
[0];
598 out
->language
[1] = fileName
[1];
599 out
->country
[0] = fileName
[3];
600 out
->country
[1] = fileName
[4];
608 bool AaptGroupEntry::getOrientationName(const char* name
,
609 ResTable_config
* out
)
611 if (strcmp(name
, kWildcardName
) == 0) {
612 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
614 } else if (strcmp(name
, "port") == 0) {
615 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
617 } else if (strcmp(name
, "land") == 0) {
618 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
620 } else if (strcmp(name
, "square") == 0) {
621 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
628 bool AaptGroupEntry::getDensityName(const char* name
,
629 ResTable_config
* out
)
631 if (strcmp(name
, kWildcardName
) == 0) {
632 if (out
) out
->density
= 0;
635 char* c
= (char*)name
;
636 while (*c
>= '0' && *c
<= '9') {
640 // check that we have 'dpi' after the last digit.
641 if (toupper(c
[0]) != 'D' ||
642 toupper(c
[1]) != 'P' ||
643 toupper(c
[2]) != 'I' ||
648 // temporarily replace the first letter with \0 to
657 if (out
) out
->density
= d
;
664 bool AaptGroupEntry::getTouchscreenName(const char* name
,
665 ResTable_config
* out
)
667 if (strcmp(name
, kWildcardName
) == 0) {
668 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
670 } else if (strcmp(name
, "notouch") == 0) {
671 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
673 } else if (strcmp(name
, "stylus") == 0) {
674 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
676 } else if (strcmp(name
, "finger") == 0) {
677 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
684 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
685 ResTable_config
* out
)
689 if (strcmp(name
, kWildcardName
) == 0) {
690 mask
= out
->MASK_KEYSHIDDEN
;
691 value
= out
->KEYSHIDDEN_ANY
;
692 } else if (strcmp(name
, "keysexposed") == 0) {
693 mask
= out
->MASK_KEYSHIDDEN
;
694 value
= out
->KEYSHIDDEN_NO
;
695 } else if (strcmp(name
, "keyshidden") == 0) {
696 mask
= out
->MASK_KEYSHIDDEN
;
697 value
= out
->KEYSHIDDEN_YES
;
698 } else if (strcmp(name
, "keyssoft") == 0) {
699 mask
= out
->MASK_KEYSHIDDEN
;
700 value
= out
->KEYSHIDDEN_SOFT
;
704 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
711 bool AaptGroupEntry::getKeyboardName(const char* name
,
712 ResTable_config
* out
)
714 if (strcmp(name
, kWildcardName
) == 0) {
715 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
717 } else if (strcmp(name
, "nokeys") == 0) {
718 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
720 } else if (strcmp(name
, "qwerty") == 0) {
721 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
723 } else if (strcmp(name
, "12key") == 0) {
724 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
731 bool AaptGroupEntry::getNavigationName(const char* name
,
732 ResTable_config
* out
)
734 if (strcmp(name
, kWildcardName
) == 0) {
735 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
737 } else if (strcmp(name
, "nonav") == 0) {
738 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
740 } else if (strcmp(name
, "dpad") == 0) {
741 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
743 } else if (strcmp(name
, "trackball") == 0) {
744 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
746 } else if (strcmp(name
, "wheel") == 0) {
747 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
754 bool AaptGroupEntry::getScreenSizeName(const char* name
,
755 ResTable_config
* out
)
757 if (strcmp(name
, kWildcardName
) == 0) {
759 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
760 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
765 const char* x
= name
;
766 while (*x
>= '0' && *x
<= '9') x
++;
767 if (x
== name
|| *x
!= 'x') return false;
768 String8
xName(name
, x
-name
);
772 while (*y
>= '0' && *y
<= '9') y
++;
773 if (y
== name
|| *y
!= 0) return false;
774 String8
yName(x
, y
-x
);
776 uint16_t w
= (uint16_t)atoi(xName
.string());
777 uint16_t h
= (uint16_t)atoi(yName
.string());
783 out
->screenWidth
= w
;
784 out
->screenHeight
= h
;
790 bool AaptGroupEntry::getVersionName(const char* name
,
791 ResTable_config
* out
)
793 if (strcmp(name
, kWildcardName
) == 0) {
795 out
->sdkVersion
= out
->SDKVERSION_ANY
;
796 out
->minorVersion
= out
->MINORVERSION_ANY
;
806 const char* s
= name
;
807 while (*s
>= '0' && *s
<= '9') s
++;
808 if (s
== name
|| *s
!= 0) return false;
809 String8
sdkName(name
, s
-name
);
812 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
813 out
->minorVersion
= 0;
819 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
821 int v
= mcc
.compare(o
.mcc
);
822 if (v
== 0) v
= mnc
.compare(o
.mnc
);
823 if (v
== 0) v
= locale
.compare(o
.locale
);
824 if (v
== 0) v
= vendor
.compare(o
.vendor
);
825 if (v
== 0) v
= orientation
.compare(o
.orientation
);
826 if (v
== 0) v
= density
.compare(o
.density
);
827 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
828 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
829 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
830 if (v
== 0) v
= navigation
.compare(o
.navigation
);
831 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
832 if (v
== 0) v
= version
.compare(o
.version
);
836 ResTable_config
AaptGroupEntry::toParams() const
838 ResTable_config params
;
839 memset(¶ms
, 0, sizeof(params
));
840 getMccName(mcc
.string(), ¶ms
);
841 getMncName(mnc
.string(), ¶ms
);
842 getLocaleName(locale
.string(), ¶ms
);
843 getOrientationName(orientation
.string(), ¶ms
);
844 getDensityName(density
.string(), ¶ms
);
845 getTouchscreenName(touchscreen
.string(), ¶ms
);
846 getKeysHiddenName(keysHidden
.string(), ¶ms
);
847 getKeyboardName(keyboard
.string(), ¶ms
);
848 getNavigationName(navigation
.string(), ¶ms
);
849 getScreenSizeName(screenSize
.string(), ¶ms
);
850 getVersionName(version
.string(), ¶ms
);
854 // =========================================================================
855 // =========================================================================
856 // =========================================================================
858 void* AaptFile::editData(size_t size
)
860 if (size
<= mBufferSize
) {
864 size_t allocSize
= (size
*3)/2;
865 void* buf
= realloc(mData
, allocSize
);
871 mBufferSize
= allocSize
;
875 void* AaptFile::editData(size_t* outSize
)
878 *outSize
= mDataSize
;
883 void* AaptFile::padData(size_t wordSize
)
885 const size_t extra
= mDataSize%wordSize
;
890 size_t initial
= mDataSize
;
891 void* data
= editData(initial
+(wordSize
-extra
));
893 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
898 status_t
AaptFile::writeData(const void* data
, size_t size
)
900 size_t end
= mDataSize
;
901 size_t total
= size
+ end
;
902 void* buf
= editData(total
);
904 return UNKNOWN_ERROR
;
906 memcpy(((char*)buf
)+end
, data
, size
);
910 void AaptFile::clearData()
912 if (mData
!= NULL
) free(mData
);
918 String8
AaptFile::getPrintableSource() const
921 String8
name(mGroupEntry
.locale
.string());
922 name
.appendPath(mGroupEntry
.vendor
.string());
923 name
.appendPath(mPath
);
924 name
.append(" #generated");
930 // =========================================================================
931 // =========================================================================
932 // =========================================================================
934 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
936 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
938 mFiles
.add(file
->getGroupEntry(), file
);
942 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
943 getPrintableSource().string());
944 return UNKNOWN_ERROR
;
947 void AaptGroup::removeFile(size_t index
)
949 mFiles
.removeItemsAt(index
);
952 void AaptGroup::print() const
954 printf(" %s\n", getPath().string());
955 const size_t N
=mFiles
.size();
957 for (i
=0; i
<N
; i
++) {
958 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
959 const AaptGroupEntry
& e
= file
->getGroupEntry();
960 if (file
->hasData()) {
961 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
962 (int)file
->getSize());
964 printf(" Src: %s\n", file
->getPrintableSource().string());
969 String8
AaptGroup::getPrintableSource() const
971 if (mFiles
.size() > 0) {
972 // Arbitrarily pull the first source file out of the list.
973 return mFiles
.valueAt(0)->getPrintableSource();
976 // Should never hit this case, but to be safe...
981 // =========================================================================
982 // =========================================================================
983 // =========================================================================
985 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
987 if (mFiles
.indexOfKey(name
) >= 0) {
988 return ALREADY_EXISTS
;
990 mFiles
.add(name
, file
);
994 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
996 if (mDirs
.indexOfKey(name
) >= 0) {
997 return ALREADY_EXISTS
;
999 mDirs
.add(name
, dir
);
1003 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1006 String8 remain
= path
;
1008 sp
<AaptDir
> subdir
= this;
1009 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1010 subdir
= subdir
->makeDir(name
);
1013 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1015 return subdir
->mDirs
.valueAt(i
);
1017 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1018 subdir
->mDirs
.add(name
, dir
);
1022 void AaptDir::removeFile(const String8
& name
)
1024 mFiles
.removeItem(name
);
1027 void AaptDir::removeDir(const String8
& name
)
1029 mDirs
.removeItem(name
);
1032 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1034 sp
<AaptGroup
> origGroup
;
1036 // Find and remove the given file with shear, brute force!
1037 const size_t NG
= mFiles
.size();
1039 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1040 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1041 const size_t NF
= g
->getFiles().size();
1042 for (size_t j
=0; j
<NF
; j
++) {
1043 if (g
->getFiles().valueAt(j
) == file
) {
1047 mFiles
.removeItemsAt(i
);
1054 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1056 // Place the file under its new name.
1057 if (origGroup
!= NULL
) {
1058 return addLeafFile(newName
, file
);
1064 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1066 sp
<AaptGroup
> group
;
1067 if (mFiles
.indexOfKey(leafName
) >= 0) {
1068 group
= mFiles
.valueFor(leafName
);
1070 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1071 mFiles
.add(leafName
, group
);
1074 return group
->addFile(file
);
1077 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1078 const AaptGroupEntry
& kind
, const String8
& resType
)
1080 Vector
<String8
> fileNames
;
1085 dir
= opendir(srcDir
.string());
1087 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1088 return UNKNOWN_ERROR
;
1092 * Slurp the filenames out of the directory.
1095 struct dirent
* entry
;
1097 entry
= readdir(dir
);
1101 if (isHidden(srcDir
.string(), entry
->d_name
))
1104 fileNames
.add(String8(entry
->d_name
));
1113 * Stash away the files and recursively descend into subdirectories.
1115 const size_t N
= fileNames
.size();
1117 for (i
= 0; i
< N
; i
++) {
1118 String8
pathName(srcDir
);
1121 pathName
.appendPath(fileNames
[i
].string());
1122 type
= getFileType(pathName
.string());
1123 if (type
== kFileTypeDirectory
) {
1125 bool notAdded
= false;
1126 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1127 subdir
= mDirs
.valueFor(fileNames
[i
]);
1129 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1132 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1134 if (res
< NO_ERROR
) {
1137 if (res
> 0 && notAdded
) {
1138 mDirs
.add(fileNames
[i
], subdir
);
1141 } else if (type
== kFileTypeRegular
) {
1142 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1143 status_t err
= addLeafFile(fileNames
[i
], file
);
1144 if (err
!= NO_ERROR
) {
1151 if (bundle
->getVerbose())
1152 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1159 status_t
AaptDir::validate() const
1161 const size_t NF
= mFiles
.size();
1162 const size_t ND
= mDirs
.size();
1164 for (i
= 0; i
< NF
; i
++) {
1165 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1166 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1167 "Invalid filename. Unable to add.");
1168 return UNKNOWN_ERROR
;
1172 for (j
= i
+1; j
< NF
; j
++) {
1173 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1174 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1175 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1176 "File is case-insensitive equivalent to: %s",
1177 mFiles
.valueAt(j
)->getPrintableSource().string());
1178 return UNKNOWN_ERROR
;
1181 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1182 // (this is mostly caught by the "marked" stuff, below)
1185 for (j
= 0; j
< ND
; j
++) {
1186 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1187 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1188 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1189 "File conflicts with dir from: %s",
1190 mDirs
.valueAt(j
)->getPrintableSource().string());
1191 return UNKNOWN_ERROR
;
1196 for (i
= 0; i
< ND
; i
++) {
1197 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1198 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1199 "Invalid directory name, unable to add.");
1200 return UNKNOWN_ERROR
;
1204 for (j
= i
+1; j
< ND
; j
++) {
1205 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1206 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1207 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1208 "Directory is case-insensitive equivalent to: %s",
1209 mDirs
.valueAt(j
)->getPrintableSource().string());
1210 return UNKNOWN_ERROR
;
1214 status_t err
= mDirs
.valueAt(i
)->validate();
1215 if (err
!= NO_ERROR
) {
1223 void AaptDir::print() const
1225 const size_t ND
=getDirs().size();
1227 for (i
=0; i
<ND
; i
++) {
1228 getDirs().valueAt(i
)->print();
1231 const size_t NF
=getFiles().size();
1232 for (i
=0; i
<NF
; i
++) {
1233 getFiles().valueAt(i
)->print();
1237 String8
AaptDir::getPrintableSource() const
1239 if (mFiles
.size() > 0) {
1240 // Arbitrarily pull the first file out of the list as the source dir.
1241 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1243 if (mDirs
.size() > 0) {
1244 // Or arbitrarily pull the first dir out of the list as the source dir.
1245 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1248 // Should never hit this case, but to be safe...
1253 // =========================================================================
1254 // =========================================================================
1255 // =========================================================================
1257 sp
<AaptFile
> AaptAssets::addFile(
1258 const String8
& filePath
, const AaptGroupEntry
& entry
,
1259 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1260 const String8
& resType
)
1262 sp
<AaptDir
> dir
= this;
1263 sp
<AaptGroup
> group
;
1265 String8 root
, remain(filePath
), partialPath
;
1266 while (remain
.length() > 0) {
1267 root
= remain
.walkPath(&remain
);
1268 partialPath
.appendPath(root
);
1270 const String8
rootStr(root
);
1272 if (remain
.length() == 0) {
1273 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1275 group
= dir
->getFiles().valueAt(i
);
1277 group
= new AaptGroup(rootStr
, filePath
);
1278 status_t res
= dir
->addFile(rootStr
, group
);
1279 if (res
!= NO_ERROR
) {
1283 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1284 status_t res
= group
->addFile(file
);
1285 if (res
!= NO_ERROR
) {
1291 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1293 dir
= dir
->getDirs().valueAt(i
);
1295 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1296 status_t res
= dir
->addDir(rootStr
, subdir
);
1297 if (res
!= NO_ERROR
) {
1305 mGroupEntries
.add(entry
);
1306 if (outGroup
) *outGroup
= group
;
1310 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1311 const sp
<AaptFile
>& file
, const String8
& resType
)
1313 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1314 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1315 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1316 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1319 subdir
->addFile(leafName
, grr
);
1323 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1332 const int N
= bundle
->getFileSpecCount();
1335 * If a package manifest was specified, include that first.
1337 if (bundle
->getAndroidManifestFile() != NULL
) {
1338 // place at root of zip.
1339 String8
srcFile(bundle
->getAndroidManifestFile());
1340 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1346 * If a directory of custom assets was supplied, slurp 'em up.
1348 if (bundle
->getAssetSourceDir()) {
1349 const char* assetDir
= bundle
->getAssetSourceDir();
1351 FileType type
= getFileType(assetDir
);
1352 if (type
== kFileTypeNonexistent
) {
1353 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1354 return UNKNOWN_ERROR
;
1356 if (type
!= kFileTypeDirectory
) {
1357 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1358 return UNKNOWN_ERROR
;
1361 String8
assetRoot(assetDir
);
1362 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1363 AaptGroupEntry group
;
1364 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1371 mGroupEntries
.add(group
);
1373 totalCount
+= count
;
1375 if (bundle
->getVerbose())
1376 printf("Found %d custom asset file%s in %s\n",
1377 count
, (count
==1) ? "" : "s", assetDir
);
1381 * If a directory of resource-specific assets was supplied, slurp 'em up.
1383 res
= bundle
->getResourceSourceDir();
1385 type
= getFileType(res
);
1386 if (type
== kFileTypeNonexistent
) {
1387 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1388 return UNKNOWN_ERROR
;
1390 if (type
== kFileTypeDirectory
) {
1391 count
= slurpResourceTree(bundle
, String8(res
));
1397 totalCount
+= count
;
1400 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1401 return UNKNOWN_ERROR
;
1406 * Now do any additional raw files.
1408 for (int arg
=0; arg
<N
; arg
++) {
1409 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1411 FileType type
= getFileType(assetDir
);
1412 if (type
== kFileTypeNonexistent
) {
1413 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1414 return UNKNOWN_ERROR
;
1416 if (type
!= kFileTypeDirectory
) {
1417 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1418 return UNKNOWN_ERROR
;
1421 String8
assetRoot(assetDir
);
1423 if (bundle
->getVerbose())
1424 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1427 * Do a recursive traversal of subdir tree. We don't make any
1428 * guarantees about ordering, so we're okay with an inorder search
1429 * using whatever order the OS happens to hand back to us.
1431 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1433 /* failure; report error and remove archive */
1437 totalCount
+= count
;
1439 if (bundle
->getVerbose())
1440 printf("Found %d asset file%s in %s\n",
1441 count
, (count
==1) ? "" : "s", assetDir
);
1445 if (count
!= NO_ERROR
) {
1455 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1456 const AaptGroupEntry
& kind
,
1457 const String8
& resType
)
1459 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1461 mGroupEntries
.add(kind
);
1467 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1471 DIR* dir
= opendir(srcDir
.string());
1473 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1474 return UNKNOWN_ERROR
;
1480 * Run through the directory, looking for dirs that match the
1484 struct dirent
* entry
= readdir(dir
);
1485 if (entry
== NULL
) {
1489 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1493 String8
subdirName(srcDir
);
1494 subdirName
.appendPath(entry
->d_name
);
1496 AaptGroupEntry group
;
1498 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1500 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1506 FileType type
= getFileType(subdirName
.string());
1508 if (type
== kFileTypeDirectory
) {
1509 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1510 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1517 mGroupEntries
.add(group
);
1523 if (bundle
->getVerbose()) {
1524 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1540 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1543 SortedVector
<AaptGroupEntry
> entries
;
1545 ZipFile
* zip
= new ZipFile
;
1546 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1547 if (err
!= NO_ERROR
) {
1548 fprintf(stderr
, "error opening zip file %s\n", filename
);
1554 const int N
= zip
->getNumEntries();
1555 for (int i
=0; i
<N
; i
++) {
1556 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1557 if (entry
->getDeleted()) {
1561 String8
entryName(entry
->getFileName());
1563 String8 dirName
= entryName
.getPathDir();
1564 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1567 AaptGroupEntry kind
;
1570 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1571 // these are the resources, pull their type out of the directory name
1572 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1574 // these are untyped and don't have an AaptGroupEntry
1576 if (entries
.indexOf(kind
) < 0) {
1578 mGroupEntries
.add(kind
);
1581 // use the one from the zip file if they both exist.
1582 dir
->removeFile(entryName
.getPathLeaf());
1584 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1585 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1586 if (err
!= NO_ERROR
) {
1587 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1591 file
->setCompressionMethod(entry
->getCompressionMethod());
1594 if (entryName
== "AndroidManifest.xml") {
1595 printf("AndroidManifest.xml\n");
1597 printf("\n\nfile: %s\n", entryName
.string());
1600 size_t len
= entry
->getUncompressedLen();
1601 void* data
= zip
->uncompress(entry
);
1602 void* buf
= file
->editData(len
);
1603 memcpy(buf
, data
, len
);
1607 const unsigned char* p
= (unsigned char*)data
;
1608 const unsigned char* end
= p
+len
;
1610 for (int i
=0; i
<32 && p
< end
; i
++) {
1611 printf("0x%03x ", i
*0x10 + OFF
);
1612 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1613 printf(" %02x", *p
);
1630 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1632 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1634 sym
= new AaptSymbols();
1635 mSymbols
.add(name
, sym
);
1640 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1642 if (!mHaveIncludedAssets
) {
1643 // Add in all includes.
1644 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1645 const size_t N
=incl
.size();
1646 for (size_t i
=0; i
<N
; i
++) {
1647 if (bundle
->getVerbose())
1648 printf("Including resources from package: %s\n", incl
[i
]);
1649 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1650 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1652 return UNKNOWN_ERROR
;
1655 mHaveIncludedAssets
= true;
1661 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1663 const ResTable
& res
= getIncludedResources();
1665 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1668 const ResTable
& AaptAssets::getIncludedResources() const
1670 return mIncludedAssets
.getResources(false);
1673 void AaptAssets::print() const
1675 printf("Locale/Vendor pairs:\n");
1676 const size_t N
=mGroupEntries
.size();
1677 for (size_t i
=0; i
<N
; i
++) {
1679 mGroupEntries
.itemAt(i
).locale
.string(),
1680 mGroupEntries
.itemAt(i
).vendor
.string());
1683 printf("\nFiles:\n");
1688 valid_symbol_name(const String8
& symbol
)
1690 static char const * const KEYWORDS
[] = {
1691 "abstract", "assert", "boolean", "break",
1692 "byte", "case", "catch", "char", "class", "const", "continue",
1693 "default", "do", "double", "else", "enum", "extends", "final",
1694 "finally", "float", "for", "goto", "if", "implements", "import",
1695 "instanceof", "int", "interface", "long", "native", "new", "package",
1696 "private", "protected", "public", "return", "short", "static",
1697 "strictfp", "super", "switch", "synchronized", "this", "throw",
1698 "throws", "transient", "try", "void", "volatile", "while",
1699 "true", "false", "null",
1702 const char*const* k
= KEYWORDS
;
1703 const char*const s
= symbol
.string();
1705 if (0 == strcmp(s
, *k
)) {