]>
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 (getVersionName(part
.string(), &config
)) {
192 *axis
= AXIS_VERSION
;
193 *value
= config
.version
;
201 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
203 Vector
<String8
> parts
;
205 String8 mcc
, mnc
, loc
, orient
, den
, touch
, key
, keysHidden
, nav
, size
, vers
;
209 while (NULL
!= (q
= strchr(p
, '-'))) {
213 //printf("part: %s\n", parts[parts.size()-1].string());
219 //printf("part: %s\n", parts[parts.size()-1].string());
221 const int N
= parts
.size();
223 String8 part
= parts
[index
];
226 if (!isValidResourceType(part
)) {
238 if (getMccName(part
.string())) {
247 //printf("not mcc: %s\n", part.string());
251 if (getMncName(part
.string())) {
260 //printf("not mcc: %s\n", part.string());
264 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
273 //printf("not language: %s\n", part.string());
278 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
281 loc
+= part
.string() + 1;
289 //printf("not region: %s\n", part.string());
293 if (getOrientationName(part
.string())) {
302 //printf("not orientation: %s\n", part.string());
306 if (getDensityName(part
.string())) {
315 //printf("not density: %s\n", part.string());
319 if (getTouchscreenName(part
.string())) {
328 //printf("not touchscreen: %s\n", part.string());
332 if (getKeysHiddenName(part
.string())) {
341 //printf("not keysHidden: %s\n", part.string());
345 if (getKeyboardName(part
.string())) {
354 //printf("not keyboard: %s\n", part.string());
357 if (getNavigationName(part
.string())) {
366 //printf("not navigation: %s\n", part.string());
369 if (getScreenSizeName(part
.string())) {
378 //printf("not screen size: %s\n", part.string());
381 if (getVersionName(part
.string())) {
390 //printf("not version: %s\n", part.string());
393 // if there are extra parts, it doesn't match
400 this->orientation
= orient
;
402 this->touchscreen
= touch
;
403 this->keysHidden
= keysHidden
;
404 this->keyboard
= key
;
405 this->navigation
= nav
;
406 this->screenSize
= size
;
407 this->version
= vers
;
409 // what is this anyway?
416 AaptGroupEntry::toString() const
418 String8 s
= this->mcc
;
424 s
+= this->orientation
;
443 AaptGroupEntry::toDirName(const String8
& resType
) const
446 if (this->mcc
!= "") {
450 if (this->mnc
!= "") {
454 if (this->locale
!= "") {
458 if (this->orientation
!= "") {
462 if (this->density
!= "") {
466 if (this->touchscreen
!= "") {
470 if (this->keysHidden
!= "") {
474 if (this->keyboard
!= "") {
478 if (this->navigation
!= "") {
482 if (this->screenSize
!= "") {
486 if (this->version
!= "") {
494 bool AaptGroupEntry::getMccName(const char* name
,
495 ResTable_config
* out
)
497 if (strcmp(name
, kWildcardName
) == 0) {
498 if (out
) out
->mcc
= 0;
501 const char* c
= name
;
502 if (tolower(*c
) != 'm') return false;
504 if (tolower(*c
) != 'c') return false;
506 if (tolower(*c
) != 'c') return false;
511 while (*c
>= '0' && *c
<= '9') {
514 if (*c
!= 0) return false;
515 if (c
-val
!= 3) return false;
519 if (out
) out
->mcc
= d
;
526 bool AaptGroupEntry::getMncName(const char* name
,
527 ResTable_config
* out
)
529 if (strcmp(name
, kWildcardName
) == 0) {
530 if (out
) out
->mcc
= 0;
533 const char* c
= name
;
534 if (tolower(*c
) != 'm') return false;
536 if (tolower(*c
) != 'n') return false;
538 if (tolower(*c
) != 'c') return false;
543 while (*c
>= '0' && *c
<= '9') {
546 if (*c
!= 0) return false;
547 if (c
-val
== 0 || c
-val
> 3) return false;
551 if (out
) out
->mnc
= d
;
559 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
562 * TODO: Should insist that the first two letters are lower case, and the
563 * second two are upper.
565 bool AaptGroupEntry::getLocaleName(const char* fileName
,
566 ResTable_config
* out
)
568 if (strcmp(fileName
, kWildcardName
) == 0
569 || strcmp(fileName
, kDefaultLocale
) == 0) {
571 out
->language
[0] = 0;
572 out
->language
[1] = 0;
579 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
581 out
->language
[0] = fileName
[0];
582 out
->language
[1] = fileName
[1];
589 if (strlen(fileName
) == 5 &&
590 isalpha(fileName
[0]) &&
591 isalpha(fileName
[1]) &&
592 fileName
[2] == '-' &&
593 isalpha(fileName
[3]) &&
594 isalpha(fileName
[4])) {
596 out
->language
[0] = fileName
[0];
597 out
->language
[1] = fileName
[1];
598 out
->country
[0] = fileName
[3];
599 out
->country
[1] = fileName
[4];
607 bool AaptGroupEntry::getOrientationName(const char* name
,
608 ResTable_config
* out
)
610 if (strcmp(name
, kWildcardName
) == 0) {
611 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
613 } else if (strcmp(name
, "port") == 0) {
614 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
616 } else if (strcmp(name
, "land") == 0) {
617 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
619 } else if (strcmp(name
, "square") == 0) {
620 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
627 bool AaptGroupEntry::getDensityName(const char* name
,
628 ResTable_config
* out
)
630 if (strcmp(name
, kWildcardName
) == 0) {
631 if (out
) out
->density
= 0;
634 char* c
= (char*)name
;
635 while (*c
>= '0' && *c
<= '9') {
639 // check that we have 'dpi' after the last digit.
640 if (toupper(c
[0]) != 'D' ||
641 toupper(c
[1]) != 'P' ||
642 toupper(c
[2]) != 'I' ||
647 // temporarily replace the first letter with \0 to
656 if (out
) out
->density
= d
;
663 bool AaptGroupEntry::getTouchscreenName(const char* name
,
664 ResTable_config
* out
)
666 if (strcmp(name
, kWildcardName
) == 0) {
667 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
669 } else if (strcmp(name
, "notouch") == 0) {
670 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
672 } else if (strcmp(name
, "stylus") == 0) {
673 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
675 } else if (strcmp(name
, "finger") == 0) {
676 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
683 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
684 ResTable_config
* out
)
688 if (strcmp(name
, kWildcardName
) == 0) {
689 mask
= out
->MASK_KEYSHIDDEN
;
690 value
= out
->KEYSHIDDEN_ANY
;
691 } else if (strcmp(name
, "keysexposed") == 0) {
692 mask
= out
->MASK_KEYSHIDDEN
;
693 value
= out
->KEYSHIDDEN_NO
;
694 } else if (strcmp(name
, "keyshidden") == 0) {
695 mask
= out
->MASK_KEYSHIDDEN
;
696 value
= out
->KEYSHIDDEN_YES
;
697 } else if (strcmp(name
, "keyssoft") == 0) {
698 mask
= out
->MASK_KEYSHIDDEN
;
699 value
= out
->KEYSHIDDEN_SOFT
;
703 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
710 bool AaptGroupEntry::getKeyboardName(const char* name
,
711 ResTable_config
* out
)
713 if (strcmp(name
, kWildcardName
) == 0) {
714 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
716 } else if (strcmp(name
, "nokeys") == 0) {
717 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
719 } else if (strcmp(name
, "qwerty") == 0) {
720 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
722 } else if (strcmp(name
, "12key") == 0) {
723 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
730 bool AaptGroupEntry::getNavigationName(const char* name
,
731 ResTable_config
* out
)
733 if (strcmp(name
, kWildcardName
) == 0) {
734 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
736 } else if (strcmp(name
, "nonav") == 0) {
737 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
739 } else if (strcmp(name
, "dpad") == 0) {
740 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
742 } else if (strcmp(name
, "trackball") == 0) {
743 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
745 } else if (strcmp(name
, "wheel") == 0) {
746 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
753 bool AaptGroupEntry::getScreenSizeName(const char* name
,
754 ResTable_config
* out
)
756 if (strcmp(name
, kWildcardName
) == 0) {
758 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
759 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
764 const char* x
= name
;
765 while (*x
>= '0' && *x
<= '9') x
++;
766 if (x
== name
|| *x
!= 'x') return false;
767 String8
xName(name
, x
-name
);
771 while (*y
>= '0' && *y
<= '9') y
++;
772 if (y
== name
|| *y
!= 0) return false;
773 String8
yName(x
, y
-x
);
775 uint16_t w
= (uint16_t)atoi(xName
.string());
776 uint16_t h
= (uint16_t)atoi(yName
.string());
782 out
->screenWidth
= w
;
783 out
->screenHeight
= h
;
789 bool AaptGroupEntry::getVersionName(const char* name
,
790 ResTable_config
* out
)
792 if (strcmp(name
, kWildcardName
) == 0) {
794 out
->sdkVersion
= out
->SDKVERSION_ANY
;
795 out
->minorVersion
= out
->MINORVERSION_ANY
;
805 const char* s
= name
;
806 while (*s
>= '0' && *s
<= '9') s
++;
807 if (s
== name
|| *s
!= 0) return false;
808 String8
sdkName(name
, s
-name
);
811 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
812 out
->minorVersion
= 0;
818 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
820 int v
= mcc
.compare(o
.mcc
);
821 if (v
== 0) v
= mnc
.compare(o
.mnc
);
822 if (v
== 0) v
= locale
.compare(o
.locale
);
823 if (v
== 0) v
= vendor
.compare(o
.vendor
);
824 if (v
== 0) v
= orientation
.compare(o
.orientation
);
825 if (v
== 0) v
= density
.compare(o
.density
);
826 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
827 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
828 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
829 if (v
== 0) v
= navigation
.compare(o
.navigation
);
830 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
831 if (v
== 0) v
= version
.compare(o
.version
);
835 ResTable_config
AaptGroupEntry::toParams() const
837 ResTable_config params
;
838 memset(¶ms
, 0, sizeof(params
));
839 getMccName(mcc
.string(), ¶ms
);
840 getMncName(mnc
.string(), ¶ms
);
841 getLocaleName(locale
.string(), ¶ms
);
842 getOrientationName(orientation
.string(), ¶ms
);
843 getDensityName(density
.string(), ¶ms
);
844 getTouchscreenName(touchscreen
.string(), ¶ms
);
845 getKeysHiddenName(keysHidden
.string(), ¶ms
);
846 getKeyboardName(keyboard
.string(), ¶ms
);
847 getNavigationName(navigation
.string(), ¶ms
);
848 getScreenSizeName(screenSize
.string(), ¶ms
);
849 getVersionName(version
.string(), ¶ms
);
853 // =========================================================================
854 // =========================================================================
855 // =========================================================================
857 void* AaptFile::editData(size_t size
)
859 if (size
<= mBufferSize
) {
863 size_t allocSize
= (size
*3)/2;
864 void* buf
= realloc(mData
, allocSize
);
870 mBufferSize
= allocSize
;
874 void* AaptFile::editData(size_t* outSize
)
877 *outSize
= mDataSize
;
882 void* AaptFile::padData(size_t wordSize
)
884 const size_t extra
= mDataSize%wordSize
;
889 size_t initial
= mDataSize
;
890 void* data
= editData(initial
+(wordSize
-extra
));
892 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
897 status_t
AaptFile::writeData(const void* data
, size_t size
)
899 size_t end
= mDataSize
;
900 size_t total
= size
+ end
;
901 void* buf
= editData(total
);
903 return UNKNOWN_ERROR
;
905 memcpy(((char*)buf
)+end
, data
, size
);
909 void AaptFile::clearData()
911 if (mData
!= NULL
) free(mData
);
917 String8
AaptFile::getPrintableSource() const
920 String8
name(mGroupEntry
.locale
.string());
921 name
.appendPath(mGroupEntry
.vendor
.string());
922 name
.appendPath(mPath
);
923 name
.append(" #generated");
929 // =========================================================================
930 // =========================================================================
931 // =========================================================================
933 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
935 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
937 mFiles
.add(file
->getGroupEntry(), file
);
941 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
942 getPrintableSource().string());
943 return UNKNOWN_ERROR
;
946 void AaptGroup::removeFile(size_t index
)
948 mFiles
.removeItemsAt(index
);
951 void AaptGroup::print() const
953 printf(" %s\n", getPath().string());
954 const size_t N
=mFiles
.size();
956 for (i
=0; i
<N
; i
++) {
957 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
958 const AaptGroupEntry
& e
= file
->getGroupEntry();
959 if (file
->hasData()) {
960 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
961 (int)file
->getSize());
963 printf(" Src: %s\n", file
->getPrintableSource().string());
968 String8
AaptGroup::getPrintableSource() const
970 if (mFiles
.size() > 0) {
971 // Arbitrarily pull the first source file out of the list.
972 return mFiles
.valueAt(0)->getPrintableSource();
975 // Should never hit this case, but to be safe...
980 // =========================================================================
981 // =========================================================================
982 // =========================================================================
984 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
986 if (mFiles
.indexOfKey(name
) >= 0) {
987 return ALREADY_EXISTS
;
989 mFiles
.add(name
, file
);
993 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
995 if (mDirs
.indexOfKey(name
) >= 0) {
996 return ALREADY_EXISTS
;
998 mDirs
.add(name
, dir
);
1002 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1005 String8 remain
= path
;
1007 sp
<AaptDir
> subdir
= this;
1008 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1009 subdir
= subdir
->makeDir(name
);
1012 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1014 return subdir
->mDirs
.valueAt(i
);
1016 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1017 subdir
->mDirs
.add(name
, dir
);
1021 void AaptDir::removeFile(const String8
& name
)
1023 mFiles
.removeItem(name
);
1026 void AaptDir::removeDir(const String8
& name
)
1028 mDirs
.removeItem(name
);
1031 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1033 sp
<AaptGroup
> origGroup
;
1035 // Find and remove the given file with shear, brute force!
1036 const size_t NG
= mFiles
.size();
1038 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1039 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1040 const size_t NF
= g
->getFiles().size();
1041 for (size_t j
=0; j
<NF
; j
++) {
1042 if (g
->getFiles().valueAt(j
) == file
) {
1046 mFiles
.removeItemsAt(i
);
1053 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1055 // Place the file under its new name.
1056 if (origGroup
!= NULL
) {
1057 return addLeafFile(newName
, file
);
1063 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1065 sp
<AaptGroup
> group
;
1066 if (mFiles
.indexOfKey(leafName
) >= 0) {
1067 group
= mFiles
.valueFor(leafName
);
1069 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1070 mFiles
.add(leafName
, group
);
1073 return group
->addFile(file
);
1076 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1077 const AaptGroupEntry
& kind
, const String8
& resType
)
1079 Vector
<String8
> fileNames
;
1084 dir
= opendir(srcDir
.string());
1086 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1087 return UNKNOWN_ERROR
;
1091 * Slurp the filenames out of the directory.
1094 struct dirent
* entry
;
1096 entry
= readdir(dir
);
1100 if (isHidden(srcDir
.string(), entry
->d_name
))
1103 fileNames
.add(String8(entry
->d_name
));
1112 * Stash away the files and recursively descend into subdirectories.
1114 const size_t N
= fileNames
.size();
1116 for (i
= 0; i
< N
; i
++) {
1117 String8
pathName(srcDir
);
1120 pathName
.appendPath(fileNames
[i
].string());
1121 type
= getFileType(pathName
.string());
1122 if (type
== kFileTypeDirectory
) {
1124 bool notAdded
= false;
1125 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1126 subdir
= mDirs
.valueFor(fileNames
[i
]);
1128 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1131 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1133 if (res
< NO_ERROR
) {
1136 if (res
> 0 && notAdded
) {
1137 mDirs
.add(fileNames
[i
], subdir
);
1140 } else if (type
== kFileTypeRegular
) {
1141 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1142 status_t err
= addLeafFile(fileNames
[i
], file
);
1143 if (err
!= NO_ERROR
) {
1150 if (bundle
->getVerbose())
1151 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1158 status_t
AaptDir::validate() const
1160 const size_t NF
= mFiles
.size();
1161 const size_t ND
= mDirs
.size();
1163 for (i
= 0; i
< NF
; i
++) {
1164 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1165 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1166 "Invalid filename. Unable to add.");
1167 return UNKNOWN_ERROR
;
1171 for (j
= i
+1; j
< NF
; j
++) {
1172 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1173 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1174 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1175 "File is case-insensitive equivalent to: %s",
1176 mFiles
.valueAt(j
)->getPrintableSource().string());
1177 return UNKNOWN_ERROR
;
1180 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1181 // (this is mostly caught by the "marked" stuff, below)
1184 for (j
= 0; j
< ND
; j
++) {
1185 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1186 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1187 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1188 "File conflicts with dir from: %s",
1189 mDirs
.valueAt(j
)->getPrintableSource().string());
1190 return UNKNOWN_ERROR
;
1195 for (i
= 0; i
< ND
; i
++) {
1196 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1197 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1198 "Invalid directory name, unable to add.");
1199 return UNKNOWN_ERROR
;
1203 for (j
= i
+1; j
< ND
; j
++) {
1204 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1205 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1206 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1207 "Directory is case-insensitive equivalent to: %s",
1208 mDirs
.valueAt(j
)->getPrintableSource().string());
1209 return UNKNOWN_ERROR
;
1213 status_t err
= mDirs
.valueAt(i
)->validate();
1214 if (err
!= NO_ERROR
) {
1222 void AaptDir::print() const
1224 const size_t ND
=getDirs().size();
1226 for (i
=0; i
<ND
; i
++) {
1227 getDirs().valueAt(i
)->print();
1230 const size_t NF
=getFiles().size();
1231 for (i
=0; i
<NF
; i
++) {
1232 getFiles().valueAt(i
)->print();
1236 String8
AaptDir::getPrintableSource() const
1238 if (mFiles
.size() > 0) {
1239 // Arbitrarily pull the first file out of the list as the source dir.
1240 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1242 if (mDirs
.size() > 0) {
1243 // Or arbitrarily pull the first dir out of the list as the source dir.
1244 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1247 // Should never hit this case, but to be safe...
1252 // =========================================================================
1253 // =========================================================================
1254 // =========================================================================
1256 sp
<AaptFile
> AaptAssets::addFile(
1257 const String8
& filePath
, const AaptGroupEntry
& entry
,
1258 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1259 const String8
& resType
)
1261 sp
<AaptDir
> dir
= this;
1262 sp
<AaptGroup
> group
;
1264 String8 root
, remain(filePath
), partialPath
;
1265 while (remain
.length() > 0) {
1266 root
= remain
.walkPath(&remain
);
1267 partialPath
.appendPath(root
);
1269 const String8
rootStr(root
);
1271 if (remain
.length() == 0) {
1272 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1274 group
= dir
->getFiles().valueAt(i
);
1276 group
= new AaptGroup(rootStr
, filePath
);
1277 status_t res
= dir
->addFile(rootStr
, group
);
1278 if (res
!= NO_ERROR
) {
1282 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1283 status_t res
= group
->addFile(file
);
1284 if (res
!= NO_ERROR
) {
1290 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1292 dir
= dir
->getDirs().valueAt(i
);
1294 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1295 status_t res
= dir
->addDir(rootStr
, subdir
);
1296 if (res
!= NO_ERROR
) {
1304 mGroupEntries
.add(entry
);
1305 if (outGroup
) *outGroup
= group
;
1309 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1310 const sp
<AaptFile
>& file
, const String8
& resType
)
1312 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1313 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1314 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1315 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1318 subdir
->addFile(leafName
, grr
);
1322 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1327 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1328 const size_t dirCount
=resDirs
.size();
1329 sp
<AaptAssets
> current
= this;
1331 const int N
= bundle
->getFileSpecCount();
1334 * If a package manifest was specified, include that first.
1336 if (bundle
->getAndroidManifestFile() != NULL
) {
1337 // place at root of zip.
1338 String8
srcFile(bundle
->getAndroidManifestFile());
1339 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1345 * If a directory of custom assets was supplied, slurp 'em up.
1347 if (bundle
->getAssetSourceDir()) {
1348 const char* assetDir
= bundle
->getAssetSourceDir();
1350 FileType type
= getFileType(assetDir
);
1351 if (type
== kFileTypeNonexistent
) {
1352 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1353 return UNKNOWN_ERROR
;
1355 if (type
!= kFileTypeDirectory
) {
1356 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1357 return UNKNOWN_ERROR
;
1360 String8
assetRoot(assetDir
);
1361 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1362 AaptGroupEntry group
;
1363 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1370 mGroupEntries
.add(group
);
1372 totalCount
+= count
;
1374 if (bundle
->getVerbose())
1375 printf("Found %d custom asset file%s in %s\n",
1376 count
, (count
==1) ? "" : "s", assetDir
);
1380 * If a directory of resource-specific assets was supplied, slurp 'em up.
1382 for (size_t i
=0; i
<dirCount
; i
++) {
1383 const char *res
= resDirs
[i
];
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
) {
1392 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1393 current
->setOverlay(nextOverlay
);
1394 current
= nextOverlay
;
1396 count
= current
->slurpResourceTree(bundle
, String8(res
));
1402 totalCount
+= count
;
1405 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1406 return UNKNOWN_ERROR
;
1412 * Now do any additional raw files.
1414 for (int arg
=0; arg
<N
; arg
++) {
1415 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1417 FileType type
= getFileType(assetDir
);
1418 if (type
== kFileTypeNonexistent
) {
1419 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1420 return UNKNOWN_ERROR
;
1422 if (type
!= kFileTypeDirectory
) {
1423 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1424 return UNKNOWN_ERROR
;
1427 String8
assetRoot(assetDir
);
1429 if (bundle
->getVerbose())
1430 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1433 * Do a recursive traversal of subdir tree. We don't make any
1434 * guarantees about ordering, so we're okay with an inorder search
1435 * using whatever order the OS happens to hand back to us.
1437 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1439 /* failure; report error and remove archive */
1443 totalCount
+= count
;
1445 if (bundle
->getVerbose())
1446 printf("Found %d asset file%s in %s\n",
1447 count
, (count
==1) ? "" : "s", assetDir
);
1451 if (count
!= NO_ERROR
) {
1461 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1462 const AaptGroupEntry
& kind
,
1463 const String8
& resType
)
1465 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1467 mGroupEntries
.add(kind
);
1473 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1477 DIR* dir
= opendir(srcDir
.string());
1479 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1480 return UNKNOWN_ERROR
;
1486 * Run through the directory, looking for dirs that match the
1490 struct dirent
* entry
= readdir(dir
);
1491 if (entry
== NULL
) {
1495 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1499 String8
subdirName(srcDir
);
1500 subdirName
.appendPath(entry
->d_name
);
1502 AaptGroupEntry group
;
1504 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1506 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1512 FileType type
= getFileType(subdirName
.string());
1514 if (type
== kFileTypeDirectory
) {
1515 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1516 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1523 mGroupEntries
.add(group
);
1529 if (bundle
->getVerbose()) {
1530 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1546 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1549 SortedVector
<AaptGroupEntry
> entries
;
1551 ZipFile
* zip
= new ZipFile
;
1552 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1553 if (err
!= NO_ERROR
) {
1554 fprintf(stderr
, "error opening zip file %s\n", filename
);
1560 const int N
= zip
->getNumEntries();
1561 for (int i
=0; i
<N
; i
++) {
1562 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1563 if (entry
->getDeleted()) {
1567 String8
entryName(entry
->getFileName());
1569 String8 dirName
= entryName
.getPathDir();
1570 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1573 AaptGroupEntry kind
;
1576 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1577 // these are the resources, pull their type out of the directory name
1578 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1580 // these are untyped and don't have an AaptGroupEntry
1582 if (entries
.indexOf(kind
) < 0) {
1584 mGroupEntries
.add(kind
);
1587 // use the one from the zip file if they both exist.
1588 dir
->removeFile(entryName
.getPathLeaf());
1590 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1591 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1592 if (err
!= NO_ERROR
) {
1593 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1597 file
->setCompressionMethod(entry
->getCompressionMethod());
1600 if (entryName
== "AndroidManifest.xml") {
1601 printf("AndroidManifest.xml\n");
1603 printf("\n\nfile: %s\n", entryName
.string());
1606 size_t len
= entry
->getUncompressedLen();
1607 void* data
= zip
->uncompress(entry
);
1608 void* buf
= file
->editData(len
);
1609 memcpy(buf
, data
, len
);
1613 const unsigned char* p
= (unsigned char*)data
;
1614 const unsigned char* end
= p
+len
;
1616 for (int i
=0; i
<32 && p
< end
; i
++) {
1617 printf("0x%03x ", i
*0x10 + OFF
);
1618 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1619 printf(" %02x", *p
);
1636 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1638 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1640 sym
= new AaptSymbols();
1641 mSymbols
.add(name
, sym
);
1646 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1648 if (!mHaveIncludedAssets
) {
1649 // Add in all includes.
1650 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1651 const size_t N
=incl
.size();
1652 for (size_t i
=0; i
<N
; i
++) {
1653 if (bundle
->getVerbose())
1654 printf("Including resources from package: %s\n", incl
[i
]);
1655 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1656 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1658 return UNKNOWN_ERROR
;
1661 mHaveIncludedAssets
= true;
1667 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1669 const ResTable
& res
= getIncludedResources();
1671 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1674 const ResTable
& AaptAssets::getIncludedResources() const
1676 return mIncludedAssets
.getResources(false);
1679 void AaptAssets::print() const
1681 printf("Locale/Vendor pairs:\n");
1682 const size_t N
=mGroupEntries
.size();
1683 for (size_t i
=0; i
<N
; i
++) {
1685 mGroupEntries
.itemAt(i
).locale
.string(),
1686 mGroupEntries
.itemAt(i
).vendor
.string());
1689 printf("\nFiles:\n");
1694 valid_symbol_name(const String8
& symbol
)
1696 static char const * const KEYWORDS
[] = {
1697 "abstract", "assert", "boolean", "break",
1698 "byte", "case", "catch", "char", "class", "const", "continue",
1699 "default", "do", "double", "else", "enum", "extends", "final",
1700 "finally", "float", "for", "goto", "if", "implements", "import",
1701 "instanceof", "int", "interface", "long", "native", "new", "package",
1702 "private", "protected", "public", "return", "short", "static",
1703 "strictfp", "super", "switch", "synchronized", "this", "throw",
1704 "throws", "transient", "try", "void", "volatile", "while",
1705 "true", "false", "null",
1708 const char*const* k
= KEYWORDS
;
1709 const char*const s
= symbol
.string();
1711 if (0 == strcmp(s
, *k
)) {