]>
git.saurik.com Git - android/aapt.git/blob - AaptAssets.cpp
d07e4de565fe6f17ec093d583e5aca51e92db372
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
, "picassa.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
;
701 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
708 bool AaptGroupEntry::getKeyboardName(const char* name
,
709 ResTable_config
* out
)
711 if (strcmp(name
, kWildcardName
) == 0) {
712 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
714 } else if (strcmp(name
, "nokeys") == 0) {
715 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
717 } else if (strcmp(name
, "qwerty") == 0) {
718 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
720 } else if (strcmp(name
, "12key") == 0) {
721 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
728 bool AaptGroupEntry::getNavigationName(const char* name
,
729 ResTable_config
* out
)
731 if (strcmp(name
, kWildcardName
) == 0) {
732 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
734 } else if (strcmp(name
, "nonav") == 0) {
735 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
737 } else if (strcmp(name
, "dpad") == 0) {
738 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
740 } else if (strcmp(name
, "trackball") == 0) {
741 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
743 } else if (strcmp(name
, "wheel") == 0) {
744 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
751 bool AaptGroupEntry::getScreenSizeName(const char* name
,
752 ResTable_config
* out
)
754 if (strcmp(name
, kWildcardName
) == 0) {
756 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
757 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
762 const char* x
= name
;
763 while (*x
>= '0' && *x
<= '9') x
++;
764 if (x
== name
|| *x
!= 'x') return false;
765 String8
xName(name
, x
-name
);
769 while (*y
>= '0' && *y
<= '9') y
++;
770 if (y
== name
|| *y
!= 0) return false;
771 String8
yName(x
, y
-x
);
773 uint16_t w
= (uint16_t)atoi(xName
.string());
774 uint16_t h
= (uint16_t)atoi(yName
.string());
780 out
->screenWidth
= w
;
781 out
->screenHeight
= h
;
787 bool AaptGroupEntry::getVersionName(const char* name
,
788 ResTable_config
* out
)
790 if (strcmp(name
, kWildcardName
) == 0) {
792 out
->sdkVersion
= out
->SDKVERSION_ANY
;
793 out
->minorVersion
= out
->MINORVERSION_ANY
;
803 const char* s
= name
;
804 while (*s
>= '0' && *s
<= '9') s
++;
805 if (s
== name
|| *s
!= 0) return false;
806 String8
sdkName(name
, s
-name
);
809 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
810 out
->minorVersion
= 0;
816 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
818 int v
= mcc
.compare(o
.mcc
);
819 if (v
== 0) v
= mnc
.compare(o
.mnc
);
820 if (v
== 0) v
= locale
.compare(o
.locale
);
821 if (v
== 0) v
= vendor
.compare(o
.vendor
);
822 if (v
== 0) v
= orientation
.compare(o
.orientation
);
823 if (v
== 0) v
= density
.compare(o
.density
);
824 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
825 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
826 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
827 if (v
== 0) v
= navigation
.compare(o
.navigation
);
828 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
829 if (v
== 0) v
= version
.compare(o
.version
);
833 ResTable_config
AaptGroupEntry::toParams() const
835 ResTable_config params
;
836 memset(¶ms
, 0, sizeof(params
));
837 getMccName(mcc
.string(), ¶ms
);
838 getMncName(mnc
.string(), ¶ms
);
839 getLocaleName(locale
.string(), ¶ms
);
840 getOrientationName(orientation
.string(), ¶ms
);
841 getDensityName(density
.string(), ¶ms
);
842 getTouchscreenName(touchscreen
.string(), ¶ms
);
843 getKeysHiddenName(keysHidden
.string(), ¶ms
);
844 getKeyboardName(keyboard
.string(), ¶ms
);
845 getNavigationName(navigation
.string(), ¶ms
);
846 getScreenSizeName(screenSize
.string(), ¶ms
);
847 getVersionName(version
.string(), ¶ms
);
851 // =========================================================================
852 // =========================================================================
853 // =========================================================================
855 void* AaptFile::editData(size_t size
)
857 if (size
<= mBufferSize
) {
861 size_t allocSize
= (size
*3)/2;
862 void* buf
= realloc(mData
, allocSize
);
868 mBufferSize
= allocSize
;
872 void* AaptFile::editData(size_t* outSize
)
875 *outSize
= mDataSize
;
880 void* AaptFile::padData(size_t wordSize
)
882 const size_t extra
= mDataSize%wordSize
;
887 size_t initial
= mDataSize
;
888 void* data
= editData(initial
+(wordSize
-extra
));
890 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
895 status_t
AaptFile::writeData(const void* data
, size_t size
)
897 size_t end
= mDataSize
;
898 size_t total
= size
+ end
;
899 void* buf
= editData(total
);
901 return UNKNOWN_ERROR
;
903 memcpy(((char*)buf
)+end
, data
, size
);
907 void AaptFile::clearData()
909 if (mData
!= NULL
) free(mData
);
915 String8
AaptFile::getPrintableSource() const
918 String8
name(mGroupEntry
.locale
.string());
919 name
.appendPath(mGroupEntry
.vendor
.string());
920 name
.appendPath(mPath
);
921 name
.append(" #generated");
927 // =========================================================================
928 // =========================================================================
929 // =========================================================================
931 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
933 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
935 mFiles
.add(file
->getGroupEntry(), file
);
939 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
940 getPrintableSource().string());
941 return UNKNOWN_ERROR
;
944 void AaptGroup::removeFile(size_t index
)
946 mFiles
.removeItemsAt(index
);
949 void AaptGroup::print() const
951 printf(" %s\n", getPath().string());
952 const size_t N
=mFiles
.size();
954 for (i
=0; i
<N
; i
++) {
955 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
956 const AaptGroupEntry
& e
= file
->getGroupEntry();
957 if (file
->hasData()) {
958 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
959 (int)file
->getSize());
961 printf(" Src: %s\n", file
->getPrintableSource().string());
966 String8
AaptGroup::getPrintableSource() const
968 if (mFiles
.size() > 0) {
969 // Arbitrarily pull the first source file out of the list.
970 return mFiles
.valueAt(0)->getPrintableSource();
973 // Should never hit this case, but to be safe...
978 // =========================================================================
979 // =========================================================================
980 // =========================================================================
982 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
984 if (mFiles
.indexOfKey(name
) >= 0) {
985 return ALREADY_EXISTS
;
987 mFiles
.add(name
, file
);
991 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
993 if (mDirs
.indexOfKey(name
) >= 0) {
994 return ALREADY_EXISTS
;
996 mDirs
.add(name
, dir
);
1000 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1003 String8 remain
= path
;
1005 sp
<AaptDir
> subdir
= this;
1006 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1007 subdir
= subdir
->makeDir(name
);
1010 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1012 return subdir
->mDirs
.valueAt(i
);
1014 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1015 subdir
->mDirs
.add(name
, dir
);
1019 void AaptDir::removeFile(const String8
& name
)
1021 mFiles
.removeItem(name
);
1024 void AaptDir::removeDir(const String8
& name
)
1026 mDirs
.removeItem(name
);
1029 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1031 sp
<AaptGroup
> origGroup
;
1033 // Find and remove the given file with shear, brute force!
1034 const size_t NG
= mFiles
.size();
1036 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1037 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1038 const size_t NF
= g
->getFiles().size();
1039 for (size_t j
=0; j
<NF
; j
++) {
1040 if (g
->getFiles().valueAt(j
) == file
) {
1044 mFiles
.removeItemsAt(i
);
1051 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1053 // Place the file under its new name.
1054 if (origGroup
!= NULL
) {
1055 return addLeafFile(newName
, file
);
1061 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1063 sp
<AaptGroup
> group
;
1064 if (mFiles
.indexOfKey(leafName
) >= 0) {
1065 group
= mFiles
.valueFor(leafName
);
1067 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1068 mFiles
.add(leafName
, group
);
1071 return group
->addFile(file
);
1074 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1075 const AaptGroupEntry
& kind
, const String8
& resType
)
1077 Vector
<String8
> fileNames
;
1082 dir
= opendir(srcDir
.string());
1084 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1085 return UNKNOWN_ERROR
;
1089 * Slurp the filenames out of the directory.
1092 struct dirent
* entry
;
1094 entry
= readdir(dir
);
1098 if (isHidden(srcDir
.string(), entry
->d_name
))
1101 fileNames
.add(String8(entry
->d_name
));
1110 * Stash away the files and recursively descend into subdirectories.
1112 const size_t N
= fileNames
.size();
1114 for (i
= 0; i
< N
; i
++) {
1115 String8
pathName(srcDir
);
1118 pathName
.appendPath(fileNames
[i
].string());
1119 type
= getFileType(pathName
.string());
1120 if (type
== kFileTypeDirectory
) {
1122 bool notAdded
= false;
1123 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1124 subdir
= mDirs
.valueFor(fileNames
[i
]);
1126 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1129 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1131 if (res
< NO_ERROR
) {
1134 if (res
> 0 && notAdded
) {
1135 mDirs
.add(fileNames
[i
], subdir
);
1138 } else if (type
== kFileTypeRegular
) {
1139 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1140 status_t err
= addLeafFile(fileNames
[i
], file
);
1141 if (err
!= NO_ERROR
) {
1148 if (bundle
->getVerbose())
1149 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1156 status_t
AaptDir::validate() const
1158 const size_t NF
= mFiles
.size();
1159 const size_t ND
= mDirs
.size();
1161 for (i
= 0; i
< NF
; i
++) {
1162 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1163 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1164 "Invalid filename. Unable to add.");
1165 return UNKNOWN_ERROR
;
1169 for (j
= i
+1; j
< NF
; j
++) {
1170 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1171 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1172 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1173 "File is case-insensitive equivalent to: %s",
1174 mFiles
.valueAt(j
)->getPrintableSource().string());
1175 return UNKNOWN_ERROR
;
1178 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1179 // (this is mostly caught by the "marked" stuff, below)
1182 for (j
= 0; j
< ND
; j
++) {
1183 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1184 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1185 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1186 "File conflicts with dir from: %s",
1187 mDirs
.valueAt(j
)->getPrintableSource().string());
1188 return UNKNOWN_ERROR
;
1193 for (i
= 0; i
< ND
; i
++) {
1194 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1195 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1196 "Invalid directory name, unable to add.");
1197 return UNKNOWN_ERROR
;
1201 for (j
= i
+1; j
< ND
; j
++) {
1202 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1203 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1204 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1205 "Directory is case-insensitive equivalent to: %s",
1206 mDirs
.valueAt(j
)->getPrintableSource().string());
1207 return UNKNOWN_ERROR
;
1211 status_t err
= mDirs
.valueAt(i
)->validate();
1212 if (err
!= NO_ERROR
) {
1220 void AaptDir::print() const
1222 const size_t ND
=getDirs().size();
1224 for (i
=0; i
<ND
; i
++) {
1225 getDirs().valueAt(i
)->print();
1228 const size_t NF
=getFiles().size();
1229 for (i
=0; i
<NF
; i
++) {
1230 getFiles().valueAt(i
)->print();
1234 String8
AaptDir::getPrintableSource() const
1236 if (mFiles
.size() > 0) {
1237 // Arbitrarily pull the first file out of the list as the source dir.
1238 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1240 if (mDirs
.size() > 0) {
1241 // Or arbitrarily pull the first dir out of the list as the source dir.
1242 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1245 // Should never hit this case, but to be safe...
1250 // =========================================================================
1251 // =========================================================================
1252 // =========================================================================
1254 sp
<AaptFile
> AaptAssets::addFile(
1255 const String8
& filePath
, const AaptGroupEntry
& entry
,
1256 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1257 const String8
& resType
)
1259 sp
<AaptDir
> dir
= this;
1260 sp
<AaptGroup
> group
;
1262 String8 root
, remain(filePath
), partialPath
;
1263 while (remain
.length() > 0) {
1264 root
= remain
.walkPath(&remain
);
1265 partialPath
.appendPath(root
);
1267 const String8
rootStr(root
);
1269 if (remain
.length() == 0) {
1270 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1272 group
= dir
->getFiles().valueAt(i
);
1274 group
= new AaptGroup(rootStr
, filePath
);
1275 status_t res
= dir
->addFile(rootStr
, group
);
1276 if (res
!= NO_ERROR
) {
1280 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1281 status_t res
= group
->addFile(file
);
1282 if (res
!= NO_ERROR
) {
1288 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1290 dir
= dir
->getDirs().valueAt(i
);
1292 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1293 status_t res
= dir
->addDir(rootStr
, subdir
);
1294 if (res
!= NO_ERROR
) {
1302 mGroupEntries
.add(entry
);
1303 if (outGroup
) *outGroup
= group
;
1307 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1308 const sp
<AaptFile
>& file
, const String8
& resType
)
1310 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1311 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1312 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1313 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1316 subdir
->addFile(leafName
, grr
);
1320 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1329 const int N
= bundle
->getFileSpecCount();
1332 * If a package manifest was specified, include that first.
1334 if (bundle
->getAndroidManifestFile() != NULL
) {
1335 // place at root of zip.
1336 String8
srcFile(bundle
->getAndroidManifestFile());
1337 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1343 * If a directory of custom assets was supplied, slurp 'em up.
1345 if (bundle
->getAssetSourceDir()) {
1346 const char* assetDir
= bundle
->getAssetSourceDir();
1348 FileType type
= getFileType(assetDir
);
1349 if (type
== kFileTypeNonexistent
) {
1350 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1351 return UNKNOWN_ERROR
;
1353 if (type
!= kFileTypeDirectory
) {
1354 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1355 return UNKNOWN_ERROR
;
1358 String8
assetRoot(assetDir
);
1359 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1360 AaptGroupEntry group
;
1361 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1368 mGroupEntries
.add(group
);
1370 totalCount
+= count
;
1372 if (bundle
->getVerbose())
1373 printf("Found %d custom asset file%s in %s\n",
1374 count
, (count
==1) ? "" : "s", assetDir
);
1378 * If a directory of resource-specific assets was supplied, slurp 'em up.
1380 res
= bundle
->getResourceSourceDir();
1382 type
= getFileType(res
);
1383 if (type
== kFileTypeNonexistent
) {
1384 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1385 return UNKNOWN_ERROR
;
1387 if (type
== kFileTypeDirectory
) {
1388 count
= slurpResourceTree(bundle
, String8(res
));
1394 totalCount
+= count
;
1397 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1398 return UNKNOWN_ERROR
;
1403 * Now do any additional raw files.
1405 for (int arg
=0; arg
<N
; arg
++) {
1406 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1408 FileType type
= getFileType(assetDir
);
1409 if (type
== kFileTypeNonexistent
) {
1410 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1411 return UNKNOWN_ERROR
;
1413 if (type
!= kFileTypeDirectory
) {
1414 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1415 return UNKNOWN_ERROR
;
1418 String8
assetRoot(assetDir
);
1420 if (bundle
->getVerbose())
1421 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1424 * Do a recursive traversal of subdir tree. We don't make any
1425 * guarantees about ordering, so we're okay with an inorder search
1426 * using whatever order the OS happens to hand back to us.
1428 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1430 /* failure; report error and remove archive */
1434 totalCount
+= count
;
1436 if (bundle
->getVerbose())
1437 printf("Found %d asset file%s in %s\n",
1438 count
, (count
==1) ? "" : "s", assetDir
);
1442 if (count
!= NO_ERROR
) {
1452 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1453 const AaptGroupEntry
& kind
,
1454 const String8
& resType
)
1456 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1458 mGroupEntries
.add(kind
);
1464 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1468 DIR* dir
= opendir(srcDir
.string());
1470 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1471 return UNKNOWN_ERROR
;
1477 * Run through the directory, looking for dirs that match the
1481 struct dirent
* entry
= readdir(dir
);
1482 if (entry
== NULL
) {
1486 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1490 String8
subdirName(srcDir
);
1491 subdirName
.appendPath(entry
->d_name
);
1493 AaptGroupEntry group
;
1495 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1497 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1503 FileType type
= getFileType(subdirName
.string());
1505 if (type
== kFileTypeDirectory
) {
1506 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1507 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1514 mGroupEntries
.add(group
);
1520 if (bundle
->getVerbose()) {
1521 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1537 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1540 SortedVector
<AaptGroupEntry
> entries
;
1542 ZipFile
* zip
= new ZipFile
;
1543 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1544 if (err
!= NO_ERROR
) {
1545 fprintf(stderr
, "error opening zip file %s\n", filename
);
1551 const int N
= zip
->getNumEntries();
1552 for (int i
=0; i
<N
; i
++) {
1553 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1554 if (entry
->getDeleted()) {
1558 String8
entryName(entry
->getFileName());
1560 String8 dirName
= entryName
.getPathDir();
1561 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1564 AaptGroupEntry kind
;
1567 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1568 // these are the resources, pull their type out of the directory name
1569 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1571 // these are untyped and don't have an AaptGroupEntry
1573 if (entries
.indexOf(kind
) < 0) {
1575 mGroupEntries
.add(kind
);
1578 // use the one from the zip file if they both exist.
1579 dir
->removeFile(entryName
.getPathLeaf());
1581 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1582 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1583 if (err
!= NO_ERROR
) {
1584 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1588 file
->setCompressionMethod(entry
->getCompressionMethod());
1591 if (entryName
== "AndroidManifest.xml") {
1592 printf("AndroidManifest.xml\n");
1594 printf("\n\nfile: %s\n", entryName
.string());
1597 size_t len
= entry
->getUncompressedLen();
1598 void* data
= zip
->uncompress(entry
);
1599 void* buf
= file
->editData(len
);
1600 memcpy(buf
, data
, len
);
1604 const unsigned char* p
= (unsigned char*)data
;
1605 const unsigned char* end
= p
+len
;
1607 for (int i
=0; i
<32 && p
< end
; i
++) {
1608 printf("0x%03x ", i
*0x10 + OFF
);
1609 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1610 printf(" %02x", *p
);
1627 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1629 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1631 sym
= new AaptSymbols();
1632 mSymbols
.add(name
, sym
);
1637 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1639 if (!mHaveIncludedAssets
) {
1640 // Add in all includes.
1641 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1642 const size_t N
=incl
.size();
1643 for (size_t i
=0; i
<N
; i
++) {
1644 if (bundle
->getVerbose())
1645 printf("Including resources from package: %s\n", incl
[i
]);
1646 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1647 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1649 return UNKNOWN_ERROR
;
1652 mHaveIncludedAssets
= true;
1658 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1660 const ResTable
& res
= getIncludedResources();
1662 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1665 const ResTable
& AaptAssets::getIncludedResources() const
1667 return mIncludedAssets
.getResources(false);
1670 void AaptAssets::print() const
1672 printf("Locale/Vendor pairs:\n");
1673 const size_t N
=mGroupEntries
.size();
1674 for (size_t i
=0; i
<N
; i
++) {
1676 mGroupEntries
.itemAt(i
).locale
.string(),
1677 mGroupEntries
.itemAt(i
).vendor
.string());
1680 printf("\nFiles:\n");
1685 valid_symbol_name(const String8
& symbol
)
1687 static char const * const KEYWORDS
[] = {
1688 "abstract", "assert", "boolean", "break",
1689 "byte", "case", "catch", "char", "class", "const", "continue",
1690 "default", "do", "double", "else", "enum", "extends", "final",
1691 "finally", "float", "for", "goto", "if", "implements", "import",
1692 "instanceof", "int", "interface", "long", "native", "new", "package",
1693 "private", "protected", "public", "return", "short", "static",
1694 "strictfp", "super", "switch", "synchronized", "this", "throw",
1695 "throws", "transient", "try", "void", "volatile", "while",
1696 "true", "false", "null",
1699 const char*const* k
= KEYWORDS
;
1700 const char*const s
= symbol
.string();
1702 if (0 == strcmp(s
, *k
)) {