]>
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]);
141 // screen layout size
142 if (getScreenLayoutSizeName(part
.string(), &config
)) {
143 *axis
= AXIS_SCREENLAYOUTSIZE
;
144 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
);
148 // screen layout long
149 if (getScreenLayoutLongName(part
.string(), &config
)) {
150 *axis
= AXIS_SCREENLAYOUTLONG
;
151 *value
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
);
156 if (getOrientationName(part
.string(), &config
)) {
157 *axis
= AXIS_ORIENTATION
;
158 *value
= config
.orientation
;
163 if (getDensityName(part
.string(), &config
)) {
164 *axis
= AXIS_DENSITY
;
165 *value
= config
.density
;
170 if (getTouchscreenName(part
.string(), &config
)) {
171 *axis
= AXIS_TOUCHSCREEN
;
172 *value
= config
.touchscreen
;
177 if (getKeysHiddenName(part
.string(), &config
)) {
178 *axis
= AXIS_KEYSHIDDEN
;
179 *value
= config
.inputFlags
;
184 if (getKeyboardName(part
.string(), &config
)) {
185 *axis
= AXIS_KEYBOARD
;
186 *value
= config
.keyboard
;
191 if (getNavHiddenName(part
.string(), &config
)) {
192 *axis
= AXIS_NAVHIDDEN
;
193 *value
= config
.inputFlags
;
198 if (getNavigationName(part
.string(), &config
)) {
199 *axis
= AXIS_NAVIGATION
;
200 *value
= config
.navigation
;
205 if (getScreenSizeName(part
.string(), &config
)) {
206 *axis
= AXIS_SCREENSIZE
;
207 *value
= config
.screenSize
;
212 if (getVersionName(part
.string(), &config
)) {
213 *axis
= AXIS_VERSION
;
214 *value
= config
.version
;
222 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
)
224 Vector
<String8
> parts
;
226 String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
;
227 String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
;
231 while (NULL
!= (q
= strchr(p
, '-'))) {
235 //printf("part: %s\n", parts[parts.size()-1].string());
241 //printf("part: %s\n", parts[parts.size()-1].string());
243 const int N
= parts
.size();
245 String8 part
= parts
[index
];
248 if (!isValidResourceType(part
)) {
260 if (getMccName(part
.string())) {
269 //printf("not mcc: %s\n", part.string());
273 if (getMncName(part
.string())) {
282 //printf("not mcc: %s\n", part.string());
286 if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) {
295 //printf("not language: %s\n", part.string());
300 && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) {
303 loc
+= part
.string() + 1;
311 //printf("not region: %s\n", part.string());
314 if (getScreenLayoutSizeName(part
.string())) {
323 //printf("not screen layout size: %s\n", part.string());
326 if (getScreenLayoutLongName(part
.string())) {
335 //printf("not screen layout long: %s\n", part.string());
339 if (getOrientationName(part
.string())) {
348 //printf("not orientation: %s\n", part.string());
352 if (getDensityName(part
.string())) {
361 //printf("not density: %s\n", part.string());
365 if (getTouchscreenName(part
.string())) {
374 //printf("not touchscreen: %s\n", part.string());
378 if (getKeysHiddenName(part
.string())) {
387 //printf("not keysHidden: %s\n", part.string());
391 if (getKeyboardName(part
.string())) {
400 //printf("not keyboard: %s\n", part.string());
404 if (getNavHiddenName(part
.string())) {
413 //printf("not navHidden: %s\n", part.string());
416 if (getNavigationName(part
.string())) {
425 //printf("not navigation: %s\n", part.string());
428 if (getScreenSizeName(part
.string())) {
437 //printf("not screen size: %s\n", part.string());
440 if (getVersionName(part
.string())) {
449 //printf("not version: %s\n", part.string());
452 // if there are extra parts, it doesn't match
459 this->screenLayoutSize
= layoutsize
;
460 this->screenLayoutLong
= layoutlong
;
461 this->orientation
= orient
;
463 this->touchscreen
= touch
;
464 this->keysHidden
= keysHidden
;
465 this->keyboard
= key
;
466 this->navHidden
= navHidden
;
467 this->navigation
= nav
;
468 this->screenSize
= size
;
469 this->version
= vers
;
471 // what is this anyway?
478 AaptGroupEntry::toString() const
480 String8 s
= this->mcc
;
486 s
+= screenLayoutSize
;
488 s
+= screenLayoutLong
;
490 s
+= this->orientation
;
511 AaptGroupEntry::toDirName(const String8
& resType
) const
514 if (this->mcc
!= "") {
518 if (this->mnc
!= "") {
522 if (this->locale
!= "") {
526 if (this->screenLayoutSize
!= "") {
528 s
+= screenLayoutSize
;
530 if (this->screenLayoutLong
!= "") {
532 s
+= screenLayoutLong
;
534 if (this->orientation
!= "") {
538 if (this->density
!= "") {
542 if (this->touchscreen
!= "") {
546 if (this->keysHidden
!= "") {
550 if (this->keyboard
!= "") {
554 if (this->navHidden
!= "") {
558 if (this->navigation
!= "") {
562 if (this->screenSize
!= "") {
566 if (this->version
!= "") {
574 bool AaptGroupEntry::getMccName(const char* name
,
575 ResTable_config
* out
)
577 if (strcmp(name
, kWildcardName
) == 0) {
578 if (out
) out
->mcc
= 0;
581 const char* c
= name
;
582 if (tolower(*c
) != 'm') return false;
584 if (tolower(*c
) != 'c') return false;
586 if (tolower(*c
) != 'c') return false;
591 while (*c
>= '0' && *c
<= '9') {
594 if (*c
!= 0) return false;
595 if (c
-val
!= 3) return false;
599 if (out
) out
->mcc
= d
;
606 bool AaptGroupEntry::getMncName(const char* name
,
607 ResTable_config
* out
)
609 if (strcmp(name
, kWildcardName
) == 0) {
610 if (out
) out
->mcc
= 0;
613 const char* c
= name
;
614 if (tolower(*c
) != 'm') return false;
616 if (tolower(*c
) != 'n') return false;
618 if (tolower(*c
) != 'c') return false;
623 while (*c
>= '0' && *c
<= '9') {
626 if (*c
!= 0) return false;
627 if (c
-val
== 0 || c
-val
> 3) return false;
631 if (out
) out
->mnc
= d
;
639 * Does this directory name fit the pattern of a locale dir ("en-rUS" or
642 * TODO: Should insist that the first two letters are lower case, and the
643 * second two are upper.
645 bool AaptGroupEntry::getLocaleName(const char* fileName
,
646 ResTable_config
* out
)
648 if (strcmp(fileName
, kWildcardName
) == 0
649 || strcmp(fileName
, kDefaultLocale
) == 0) {
651 out
->language
[0] = 0;
652 out
->language
[1] = 0;
659 if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) {
661 out
->language
[0] = fileName
[0];
662 out
->language
[1] = fileName
[1];
669 if (strlen(fileName
) == 5 &&
670 isalpha(fileName
[0]) &&
671 isalpha(fileName
[1]) &&
672 fileName
[2] == '-' &&
673 isalpha(fileName
[3]) &&
674 isalpha(fileName
[4])) {
676 out
->language
[0] = fileName
[0];
677 out
->language
[1] = fileName
[1];
678 out
->country
[0] = fileName
[3];
679 out
->country
[1] = fileName
[4];
687 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
,
688 ResTable_config
* out
)
690 if (strcmp(name
, kWildcardName
) == 0) {
691 if (out
) out
->screenLayout
=
692 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
693 | ResTable_config::SCREENSIZE_ANY
;
695 } else if (strcmp(name
, "small") == 0) {
696 if (out
) out
->screenLayout
=
697 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
698 | ResTable_config::SCREENSIZE_SMALL
;
700 } else if (strcmp(name
, "normal") == 0) {
701 if (out
) out
->screenLayout
=
702 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
703 | ResTable_config::SCREENSIZE_NORMAL
;
705 } else if (strcmp(name
, "large") == 0) {
706 if (out
) out
->screenLayout
=
707 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
)
708 | ResTable_config::SCREENSIZE_LARGE
;
715 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
,
716 ResTable_config
* out
)
718 if (strcmp(name
, kWildcardName
) == 0) {
719 if (out
) out
->screenLayout
=
720 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
721 | ResTable_config::SCREENLONG_ANY
;
723 } else if (strcmp(name
, "long") == 0) {
724 if (out
) out
->screenLayout
=
725 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
726 | ResTable_config::SCREENLONG_YES
;
728 } else if (strcmp(name
, "notlong") == 0) {
729 if (out
) out
->screenLayout
=
730 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
)
731 | ResTable_config::SCREENLONG_NO
;
738 bool AaptGroupEntry::getOrientationName(const char* name
,
739 ResTable_config
* out
)
741 if (strcmp(name
, kWildcardName
) == 0) {
742 if (out
) out
->orientation
= out
->ORIENTATION_ANY
;
744 } else if (strcmp(name
, "port") == 0) {
745 if (out
) out
->orientation
= out
->ORIENTATION_PORT
;
747 } else if (strcmp(name
, "land") == 0) {
748 if (out
) out
->orientation
= out
->ORIENTATION_LAND
;
750 } else if (strcmp(name
, "square") == 0) {
751 if (out
) out
->orientation
= out
->ORIENTATION_SQUARE
;
758 bool AaptGroupEntry::getDensityName(const char* name
,
759 ResTable_config
* out
)
761 if (strcmp(name
, kWildcardName
) == 0) {
762 if (out
) out
->density
= ResTable_config::DENSITY_DEFAULT
;
766 if (strcmp(name
, "nodpi") == 0) {
767 if (out
) out
->density
= ResTable_config::DENSITY_NONE
;
771 if (strcmp(name
, "ldpi") == 0) {
772 if (out
) out
->density
= ResTable_config::DENSITY_LOW
;
776 if (strcmp(name
, "mdpi") == 0) {
777 if (out
) out
->density
= ResTable_config::DENSITY_MEDIUM
;
781 if (strcmp(name
, "hdpi") == 0) {
782 if (out
) out
->density
= ResTable_config::DENSITY_HIGH
;
786 char* c
= (char*)name
;
787 while (*c
>= '0' && *c
<= '9') {
791 // check that we have 'dpi' after the last digit.
792 if (toupper(c
[0]) != 'D' ||
793 toupper(c
[1]) != 'P' ||
794 toupper(c
[2]) != 'I' ||
799 // temporarily replace the first letter with \0 to
808 if (out
) out
->density
= d
;
815 bool AaptGroupEntry::getTouchscreenName(const char* name
,
816 ResTable_config
* out
)
818 if (strcmp(name
, kWildcardName
) == 0) {
819 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_ANY
;
821 } else if (strcmp(name
, "notouch") == 0) {
822 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_NOTOUCH
;
824 } else if (strcmp(name
, "stylus") == 0) {
825 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_STYLUS
;
827 } else if (strcmp(name
, "finger") == 0) {
828 if (out
) out
->touchscreen
= out
->TOUCHSCREEN_FINGER
;
835 bool AaptGroupEntry::getKeysHiddenName(const char* name
,
836 ResTable_config
* out
)
840 if (strcmp(name
, kWildcardName
) == 0) {
841 mask
= out
->MASK_KEYSHIDDEN
;
842 value
= out
->KEYSHIDDEN_ANY
;
843 } else if (strcmp(name
, "keysexposed") == 0) {
844 mask
= out
->MASK_KEYSHIDDEN
;
845 value
= out
->KEYSHIDDEN_NO
;
846 } else if (strcmp(name
, "keyshidden") == 0) {
847 mask
= out
->MASK_KEYSHIDDEN
;
848 value
= out
->KEYSHIDDEN_YES
;
849 } else if (strcmp(name
, "keyssoft") == 0) {
850 mask
= out
->MASK_KEYSHIDDEN
;
851 value
= out
->KEYSHIDDEN_SOFT
;
855 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
862 bool AaptGroupEntry::getKeyboardName(const char* name
,
863 ResTable_config
* out
)
865 if (strcmp(name
, kWildcardName
) == 0) {
866 if (out
) out
->keyboard
= out
->KEYBOARD_ANY
;
868 } else if (strcmp(name
, "nokeys") == 0) {
869 if (out
) out
->keyboard
= out
->KEYBOARD_NOKEYS
;
871 } else if (strcmp(name
, "qwerty") == 0) {
872 if (out
) out
->keyboard
= out
->KEYBOARD_QWERTY
;
874 } else if (strcmp(name
, "12key") == 0) {
875 if (out
) out
->keyboard
= out
->KEYBOARD_12KEY
;
882 bool AaptGroupEntry::getNavHiddenName(const char* name
,
883 ResTable_config
* out
)
887 if (strcmp(name
, kWildcardName
) == 0) {
888 mask
= out
->MASK_NAVHIDDEN
;
889 value
= out
->NAVHIDDEN_ANY
;
890 } else if (strcmp(name
, "navexposed") == 0) {
891 mask
= out
->MASK_NAVHIDDEN
;
892 value
= out
->NAVHIDDEN_NO
;
893 } else if (strcmp(name
, "navhidden") == 0) {
894 mask
= out
->MASK_NAVHIDDEN
;
895 value
= out
->NAVHIDDEN_YES
;
899 if (out
) out
->inputFlags
= (out
->inputFlags
&~mask
) | value
;
906 bool AaptGroupEntry::getNavigationName(const char* name
,
907 ResTable_config
* out
)
909 if (strcmp(name
, kWildcardName
) == 0) {
910 if (out
) out
->navigation
= out
->NAVIGATION_ANY
;
912 } else if (strcmp(name
, "nonav") == 0) {
913 if (out
) out
->navigation
= out
->NAVIGATION_NONAV
;
915 } else if (strcmp(name
, "dpad") == 0) {
916 if (out
) out
->navigation
= out
->NAVIGATION_DPAD
;
918 } else if (strcmp(name
, "trackball") == 0) {
919 if (out
) out
->navigation
= out
->NAVIGATION_TRACKBALL
;
921 } else if (strcmp(name
, "wheel") == 0) {
922 if (out
) out
->navigation
= out
->NAVIGATION_WHEEL
;
929 bool AaptGroupEntry::getScreenSizeName(const char* name
,
930 ResTable_config
* out
)
932 if (strcmp(name
, kWildcardName
) == 0) {
934 out
->screenWidth
= out
->SCREENWIDTH_ANY
;
935 out
->screenHeight
= out
->SCREENHEIGHT_ANY
;
940 const char* x
= name
;
941 while (*x
>= '0' && *x
<= '9') x
++;
942 if (x
== name
|| *x
!= 'x') return false;
943 String8
xName(name
, x
-name
);
947 while (*y
>= '0' && *y
<= '9') y
++;
948 if (y
== name
|| *y
!= 0) return false;
949 String8
yName(x
, y
-x
);
951 uint16_t w
= (uint16_t)atoi(xName
.string());
952 uint16_t h
= (uint16_t)atoi(yName
.string());
958 out
->screenWidth
= w
;
959 out
->screenHeight
= h
;
965 bool AaptGroupEntry::getVersionName(const char* name
,
966 ResTable_config
* out
)
968 if (strcmp(name
, kWildcardName
) == 0) {
970 out
->sdkVersion
= out
->SDKVERSION_ANY
;
971 out
->minorVersion
= out
->MINORVERSION_ANY
;
981 const char* s
= name
;
982 while (*s
>= '0' && *s
<= '9') s
++;
983 if (s
== name
|| *s
!= 0) return false;
984 String8
sdkName(name
, s
-name
);
987 out
->sdkVersion
= (uint16_t)atoi(sdkName
.string());
988 out
->minorVersion
= 0;
994 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const
996 int v
= mcc
.compare(o
.mcc
);
997 if (v
== 0) v
= mnc
.compare(o
.mnc
);
998 if (v
== 0) v
= locale
.compare(o
.locale
);
999 if (v
== 0) v
= vendor
.compare(o
.vendor
);
1000 if (v
== 0) v
= screenLayoutSize
.compare(o
.screenLayoutSize
);
1001 if (v
== 0) v
= screenLayoutLong
.compare(o
.screenLayoutLong
);
1002 if (v
== 0) v
= orientation
.compare(o
.orientation
);
1003 if (v
== 0) v
= density
.compare(o
.density
);
1004 if (v
== 0) v
= touchscreen
.compare(o
.touchscreen
);
1005 if (v
== 0) v
= keysHidden
.compare(o
.keysHidden
);
1006 if (v
== 0) v
= keyboard
.compare(o
.keyboard
);
1007 if (v
== 0) v
= navHidden
.compare(o
.navHidden
);
1008 if (v
== 0) v
= navigation
.compare(o
.navigation
);
1009 if (v
== 0) v
= screenSize
.compare(o
.screenSize
);
1010 if (v
== 0) v
= version
.compare(o
.version
);
1014 ResTable_config
AaptGroupEntry::toParams() const
1016 ResTable_config params
;
1017 memset(¶ms
, 0, sizeof(params
));
1018 getMccName(mcc
.string(), ¶ms
);
1019 getMncName(mnc
.string(), ¶ms
);
1020 getLocaleName(locale
.string(), ¶ms
);
1021 getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
);
1022 getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
);
1023 getOrientationName(orientation
.string(), ¶ms
);
1024 getDensityName(density
.string(), ¶ms
);
1025 getTouchscreenName(touchscreen
.string(), ¶ms
);
1026 getKeysHiddenName(keysHidden
.string(), ¶ms
);
1027 getKeyboardName(keyboard
.string(), ¶ms
);
1028 getNavHiddenName(navHidden
.string(), ¶ms
);
1029 getNavigationName(navigation
.string(), ¶ms
);
1030 getScreenSizeName(screenSize
.string(), ¶ms
);
1031 getVersionName(version
.string(), ¶ms
);
1035 // =========================================================================
1036 // =========================================================================
1037 // =========================================================================
1039 void* AaptFile::editData(size_t size
)
1041 if (size
<= mBufferSize
) {
1045 size_t allocSize
= (size
*3)/2;
1046 void* buf
= realloc(mData
, allocSize
);
1052 mBufferSize
= allocSize
;
1056 void* AaptFile::editData(size_t* outSize
)
1059 *outSize
= mDataSize
;
1064 void* AaptFile::padData(size_t wordSize
)
1066 const size_t extra
= mDataSize%wordSize
;
1071 size_t initial
= mDataSize
;
1072 void* data
= editData(initial
+(wordSize
-extra
));
1074 memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
);
1079 status_t
AaptFile::writeData(const void* data
, size_t size
)
1081 size_t end
= mDataSize
;
1082 size_t total
= size
+ end
;
1083 void* buf
= editData(total
);
1085 return UNKNOWN_ERROR
;
1087 memcpy(((char*)buf
)+end
, data
, size
);
1091 void AaptFile::clearData()
1093 if (mData
!= NULL
) free(mData
);
1099 String8
AaptFile::getPrintableSource() const
1102 String8
name(mGroupEntry
.locale
.string());
1103 name
.appendPath(mGroupEntry
.vendor
.string());
1104 name
.appendPath(mPath
);
1105 name
.append(" #generated");
1111 // =========================================================================
1112 // =========================================================================
1113 // =========================================================================
1115 status_t
AaptGroup::addFile(const sp
<AaptFile
>& file
)
1117 if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) {
1118 file
->mPath
= mPath
;
1119 mFiles
.add(file
->getGroupEntry(), file
);
1123 SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
1124 getPrintableSource().string());
1125 return UNKNOWN_ERROR
;
1128 void AaptGroup::removeFile(size_t index
)
1130 mFiles
.removeItemsAt(index
);
1133 void AaptGroup::print() const
1135 printf(" %s\n", getPath().string());
1136 const size_t N
=mFiles
.size();
1138 for (i
=0; i
<N
; i
++) {
1139 sp
<AaptFile
> file
= mFiles
.valueAt(i
);
1140 const AaptGroupEntry
& e
= file
->getGroupEntry();
1141 if (file
->hasData()) {
1142 printf(" Gen: (%s) %d bytes\n", e
.toString().string(),
1143 (int)file
->getSize());
1145 printf(" Src: %s\n", file
->getPrintableSource().string());
1150 String8
AaptGroup::getPrintableSource() const
1152 if (mFiles
.size() > 0) {
1153 // Arbitrarily pull the first source file out of the list.
1154 return mFiles
.valueAt(0)->getPrintableSource();
1157 // Should never hit this case, but to be safe...
1162 // =========================================================================
1163 // =========================================================================
1164 // =========================================================================
1166 status_t
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
)
1168 if (mFiles
.indexOfKey(name
) >= 0) {
1169 return ALREADY_EXISTS
;
1171 mFiles
.add(name
, file
);
1175 status_t
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
)
1177 if (mDirs
.indexOfKey(name
) >= 0) {
1178 return ALREADY_EXISTS
;
1180 mDirs
.add(name
, dir
);
1184 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
)
1187 String8 remain
= path
;
1189 sp
<AaptDir
> subdir
= this;
1190 while (name
= remain
.walkPath(&remain
), remain
!= "") {
1191 subdir
= subdir
->makeDir(name
);
1194 ssize_t i
= subdir
->mDirs
.indexOfKey(name
);
1196 return subdir
->mDirs
.valueAt(i
);
1198 sp
<AaptDir
> dir
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
));
1199 subdir
->mDirs
.add(name
, dir
);
1203 void AaptDir::removeFile(const String8
& name
)
1205 mFiles
.removeItem(name
);
1208 void AaptDir::removeDir(const String8
& name
)
1210 mDirs
.removeItem(name
);
1213 status_t
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
)
1215 sp
<AaptGroup
> origGroup
;
1217 // Find and remove the given file with shear, brute force!
1218 const size_t NG
= mFiles
.size();
1220 for (i
=0; origGroup
== NULL
&& i
<NG
; i
++) {
1221 sp
<AaptGroup
> g
= mFiles
.valueAt(i
);
1222 const size_t NF
= g
->getFiles().size();
1223 for (size_t j
=0; j
<NF
; j
++) {
1224 if (g
->getFiles().valueAt(j
) == file
) {
1228 mFiles
.removeItemsAt(i
);
1235 //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string());
1237 // Place the file under its new name.
1238 if (origGroup
!= NULL
) {
1239 return addLeafFile(newName
, file
);
1245 status_t
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
)
1247 sp
<AaptGroup
> group
;
1248 if (mFiles
.indexOfKey(leafName
) >= 0) {
1249 group
= mFiles
.valueFor(leafName
);
1251 group
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
));
1252 mFiles
.add(leafName
, group
);
1255 return group
->addFile(file
);
1258 ssize_t
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1259 const AaptGroupEntry
& kind
, const String8
& resType
)
1261 Vector
<String8
> fileNames
;
1266 dir
= opendir(srcDir
.string());
1268 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1269 return UNKNOWN_ERROR
;
1273 * Slurp the filenames out of the directory.
1276 struct dirent
* entry
;
1278 entry
= readdir(dir
);
1282 if (isHidden(srcDir
.string(), entry
->d_name
))
1285 fileNames
.add(String8(entry
->d_name
));
1294 * Stash away the files and recursively descend into subdirectories.
1296 const size_t N
= fileNames
.size();
1298 for (i
= 0; i
< N
; i
++) {
1299 String8
pathName(srcDir
);
1302 pathName
.appendPath(fileNames
[i
].string());
1303 type
= getFileType(pathName
.string());
1304 if (type
== kFileTypeDirectory
) {
1306 bool notAdded
= false;
1307 if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) {
1308 subdir
= mDirs
.valueFor(fileNames
[i
]);
1310 subdir
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
]));
1313 ssize_t res
= subdir
->slurpFullTree(bundle
, pathName
, kind
,
1315 if (res
< NO_ERROR
) {
1318 if (res
> 0 && notAdded
) {
1319 mDirs
.add(fileNames
[i
], subdir
);
1322 } else if (type
== kFileTypeRegular
) {
1323 sp
<AaptFile
> file
= new AaptFile(pathName
, kind
, resType
);
1324 status_t err
= addLeafFile(fileNames
[i
], file
);
1325 if (err
!= NO_ERROR
) {
1332 if (bundle
->getVerbose())
1333 printf(" (ignoring non-file/dir '%s')\n", pathName
.string());
1340 status_t
AaptDir::validate() const
1342 const size_t NF
= mFiles
.size();
1343 const size_t ND
= mDirs
.size();
1345 for (i
= 0; i
< NF
; i
++) {
1346 if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) {
1347 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1348 "Invalid filename. Unable to add.");
1349 return UNKNOWN_ERROR
;
1353 for (j
= i
+1; j
< NF
; j
++) {
1354 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1355 mFiles
.valueAt(j
)->getLeaf().string()) == 0) {
1356 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1357 "File is case-insensitive equivalent to: %s",
1358 mFiles
.valueAt(j
)->getPrintableSource().string());
1359 return UNKNOWN_ERROR
;
1362 // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
1363 // (this is mostly caught by the "marked" stuff, below)
1366 for (j
= 0; j
< ND
; j
++) {
1367 if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(),
1368 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1369 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error(
1370 "File conflicts with dir from: %s",
1371 mDirs
.valueAt(j
)->getPrintableSource().string());
1372 return UNKNOWN_ERROR
;
1377 for (i
= 0; i
< ND
; i
++) {
1378 if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) {
1379 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1380 "Invalid directory name, unable to add.");
1381 return UNKNOWN_ERROR
;
1385 for (j
= i
+1; j
< ND
; j
++) {
1386 if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(),
1387 mDirs
.valueAt(j
)->getLeaf().string()) == 0) {
1388 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error(
1389 "Directory is case-insensitive equivalent to: %s",
1390 mDirs
.valueAt(j
)->getPrintableSource().string());
1391 return UNKNOWN_ERROR
;
1395 status_t err
= mDirs
.valueAt(i
)->validate();
1396 if (err
!= NO_ERROR
) {
1404 void AaptDir::print() const
1406 const size_t ND
=getDirs().size();
1408 for (i
=0; i
<ND
; i
++) {
1409 getDirs().valueAt(i
)->print();
1412 const size_t NF
=getFiles().size();
1413 for (i
=0; i
<NF
; i
++) {
1414 getFiles().valueAt(i
)->print();
1418 String8
AaptDir::getPrintableSource() const
1420 if (mFiles
.size() > 0) {
1421 // Arbitrarily pull the first file out of the list as the source dir.
1422 return mFiles
.valueAt(0)->getPrintableSource().getPathDir();
1424 if (mDirs
.size() > 0) {
1425 // Or arbitrarily pull the first dir out of the list as the source dir.
1426 return mDirs
.valueAt(0)->getPrintableSource().getPathDir();
1429 // Should never hit this case, but to be safe...
1434 // =========================================================================
1435 // =========================================================================
1436 // =========================================================================
1438 sp
<AaptFile
> AaptAssets::addFile(
1439 const String8
& filePath
, const AaptGroupEntry
& entry
,
1440 const String8
& srcDir
, sp
<AaptGroup
>* outGroup
,
1441 const String8
& resType
)
1443 sp
<AaptDir
> dir
= this;
1444 sp
<AaptGroup
> group
;
1446 String8 root
, remain(filePath
), partialPath
;
1447 while (remain
.length() > 0) {
1448 root
= remain
.walkPath(&remain
);
1449 partialPath
.appendPath(root
);
1451 const String8
rootStr(root
);
1453 if (remain
.length() == 0) {
1454 ssize_t i
= dir
->getFiles().indexOfKey(rootStr
);
1456 group
= dir
->getFiles().valueAt(i
);
1458 group
= new AaptGroup(rootStr
, filePath
);
1459 status_t res
= dir
->addFile(rootStr
, group
);
1460 if (res
!= NO_ERROR
) {
1464 file
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
);
1465 status_t res
= group
->addFile(file
);
1466 if (res
!= NO_ERROR
) {
1472 ssize_t i
= dir
->getDirs().indexOfKey(rootStr
);
1474 dir
= dir
->getDirs().valueAt(i
);
1476 sp
<AaptDir
> subdir
= new AaptDir(rootStr
, partialPath
);
1477 status_t res
= dir
->addDir(rootStr
, subdir
);
1478 if (res
!= NO_ERROR
) {
1486 mGroupEntries
.add(entry
);
1487 if (outGroup
) *outGroup
= group
;
1491 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
,
1492 const sp
<AaptFile
>& file
, const String8
& resType
)
1494 sp
<AaptDir
> res
= AaptDir::makeDir(kResString
);
1495 String8 dirname
= file
->getGroupEntry().toDirName(resType
);
1496 sp
<AaptDir
> subdir
= res
->makeDir(dirname
);
1497 sp
<AaptGroup
> grr
= new AaptGroup(leafName
, path
);
1500 subdir
->addFile(leafName
, grr
);
1504 ssize_t
AaptAssets::slurpFromArgs(Bundle
* bundle
)
1509 const Vector
<const char *>& resDirs
= bundle
->getResourceSourceDirs();
1510 const size_t dirCount
=resDirs
.size();
1511 sp
<AaptAssets
> current
= this;
1513 const int N
= bundle
->getFileSpecCount();
1516 * If a package manifest was specified, include that first.
1518 if (bundle
->getAndroidManifestFile() != NULL
) {
1519 // place at root of zip.
1520 String8
srcFile(bundle
->getAndroidManifestFile());
1521 addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(),
1527 * If a directory of custom assets was supplied, slurp 'em up.
1529 if (bundle
->getAssetSourceDir()) {
1530 const char* assetDir
= bundle
->getAssetSourceDir();
1532 FileType type
= getFileType(assetDir
);
1533 if (type
== kFileTypeNonexistent
) {
1534 fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
);
1535 return UNKNOWN_ERROR
;
1537 if (type
!= kFileTypeDirectory
) {
1538 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1539 return UNKNOWN_ERROR
;
1542 String8
assetRoot(assetDir
);
1543 sp
<AaptDir
> assetAaptDir
= makeDir(String8(kAssetDir
));
1544 AaptGroupEntry group
;
1545 count
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
,
1552 mGroupEntries
.add(group
);
1554 totalCount
+= count
;
1556 if (bundle
->getVerbose())
1557 printf("Found %d custom asset file%s in %s\n",
1558 count
, (count
==1) ? "" : "s", assetDir
);
1562 * If a directory of resource-specific assets was supplied, slurp 'em up.
1564 for (size_t i
=0; i
<dirCount
; i
++) {
1565 const char *res
= resDirs
[i
];
1567 type
= getFileType(res
);
1568 if (type
== kFileTypeNonexistent
) {
1569 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
);
1570 return UNKNOWN_ERROR
;
1572 if (type
== kFileTypeDirectory
) {
1574 sp
<AaptAssets
> nextOverlay
= new AaptAssets();
1575 current
->setOverlay(nextOverlay
);
1576 current
= nextOverlay
;
1578 count
= current
->slurpResourceTree(bundle
, String8(res
));
1584 totalCount
+= count
;
1587 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
);
1588 return UNKNOWN_ERROR
;
1594 * Now do any additional raw files.
1596 for (int arg
=0; arg
<N
; arg
++) {
1597 const char* assetDir
= bundle
->getFileSpecEntry(arg
);
1599 FileType type
= getFileType(assetDir
);
1600 if (type
== kFileTypeNonexistent
) {
1601 fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
);
1602 return UNKNOWN_ERROR
;
1604 if (type
!= kFileTypeDirectory
) {
1605 fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
);
1606 return UNKNOWN_ERROR
;
1609 String8
assetRoot(assetDir
);
1611 if (bundle
->getVerbose())
1612 printf("Processing raw dir '%s'\n", (const char*) assetDir
);
1615 * Do a recursive traversal of subdir tree. We don't make any
1616 * guarantees about ordering, so we're okay with an inorder search
1617 * using whatever order the OS happens to hand back to us.
1619 count
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8());
1621 /* failure; report error and remove archive */
1625 totalCount
+= count
;
1627 if (bundle
->getVerbose())
1628 printf("Found %d asset file%s in %s\n",
1629 count
, (count
==1) ? "" : "s", assetDir
);
1633 if (count
!= NO_ERROR
) {
1643 ssize_t
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
,
1644 const AaptGroupEntry
& kind
,
1645 const String8
& resType
)
1647 ssize_t res
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
);
1649 mGroupEntries
.add(kind
);
1655 ssize_t
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
)
1659 DIR* dir
= opendir(srcDir
.string());
1661 fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
));
1662 return UNKNOWN_ERROR
;
1668 * Run through the directory, looking for dirs that match the
1672 struct dirent
* entry
= readdir(dir
);
1673 if (entry
== NULL
) {
1677 if (isHidden(srcDir
.string(), entry
->d_name
)) {
1681 String8
subdirName(srcDir
);
1682 subdirName
.appendPath(entry
->d_name
);
1684 AaptGroupEntry group
;
1686 bool b
= group
.initFromDirName(entry
->d_name
, &resType
);
1688 fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(),
1694 FileType type
= getFileType(subdirName
.string());
1696 if (type
== kFileTypeDirectory
) {
1697 sp
<AaptDir
> dir
= makeDir(String8(entry
->d_name
));
1698 ssize_t res
= dir
->slurpFullTree(bundle
, subdirName
, group
,
1705 mGroupEntries
.add(group
);
1711 if (bundle
->getVerbose()) {
1712 fprintf(stderr
, " (ignoring file '%s')\n", subdirName
.string());
1728 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
)
1731 SortedVector
<AaptGroupEntry
> entries
;
1733 ZipFile
* zip
= new ZipFile
;
1734 status_t err
= zip
->open(filename
, ZipFile::kOpenReadOnly
);
1735 if (err
!= NO_ERROR
) {
1736 fprintf(stderr
, "error opening zip file %s\n", filename
);
1742 const int N
= zip
->getNumEntries();
1743 for (int i
=0; i
<N
; i
++) {
1744 ZipEntry
* entry
= zip
->getEntryByIndex(i
);
1745 if (entry
->getDeleted()) {
1749 String8
entryName(entry
->getFileName());
1751 String8 dirName
= entryName
.getPathDir();
1752 sp
<AaptDir
> dir
= dirName
== "" ? this : makeDir(dirName
);
1755 AaptGroupEntry kind
;
1758 if (entryName
.walkPath(&remain
) == kResourceDir
) {
1759 // these are the resources, pull their type out of the directory name
1760 kind
.initFromDirName(remain
.walkPath().string(), &resType
);
1762 // these are untyped and don't have an AaptGroupEntry
1764 if (entries
.indexOf(kind
) < 0) {
1766 mGroupEntries
.add(kind
);
1769 // use the one from the zip file if they both exist.
1770 dir
->removeFile(entryName
.getPathLeaf());
1772 sp
<AaptFile
> file
= new AaptFile(entryName
, kind
, resType
);
1773 status_t err
= dir
->addLeafFile(entryName
.getPathLeaf(), file
);
1774 if (err
!= NO_ERROR
) {
1775 fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string());
1779 file
->setCompressionMethod(entry
->getCompressionMethod());
1782 if (entryName
== "AndroidManifest.xml") {
1783 printf("AndroidManifest.xml\n");
1785 printf("\n\nfile: %s\n", entryName
.string());
1788 size_t len
= entry
->getUncompressedLen();
1789 void* data
= zip
->uncompress(entry
);
1790 void* buf
= file
->editData(len
);
1791 memcpy(buf
, data
, len
);
1795 const unsigned char* p
= (unsigned char*)data
;
1796 const unsigned char* end
= p
+len
;
1798 for (int i
=0; i
<32 && p
< end
; i
++) {
1799 printf("0x%03x ", i
*0x10 + OFF
);
1800 for (int j
=0; j
<0x10 && p
< end
; j
++) {
1801 printf(" %02x", *p
);
1818 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
)
1820 sp
<AaptSymbols
> sym
= mSymbols
.valueFor(name
);
1822 sym
= new AaptSymbols();
1823 mSymbols
.add(name
, sym
);
1828 status_t
AaptAssets::buildIncludedResources(Bundle
* bundle
)
1830 if (!mHaveIncludedAssets
) {
1831 // Add in all includes.
1832 const Vector
<const char*>& incl
= bundle
->getPackageIncludes();
1833 const size_t N
=incl
.size();
1834 for (size_t i
=0; i
<N
; i
++) {
1835 if (bundle
->getVerbose())
1836 printf("Including resources from package: %s\n", incl
[i
]);
1837 if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) {
1838 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n",
1840 return UNKNOWN_ERROR
;
1843 mHaveIncludedAssets
= true;
1849 status_t
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
)
1851 const ResTable
& res
= getIncludedResources();
1853 return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
);
1856 const ResTable
& AaptAssets::getIncludedResources() const
1858 return mIncludedAssets
.getResources(false);
1861 void AaptAssets::print() const
1863 printf("Locale/Vendor pairs:\n");
1864 const size_t N
=mGroupEntries
.size();
1865 for (size_t i
=0; i
<N
; i
++) {
1867 mGroupEntries
.itemAt(i
).locale
.string(),
1868 mGroupEntries
.itemAt(i
).vendor
.string());
1871 printf("\nFiles:\n");
1875 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
)
1877 const Vector
<sp
<AaptDir
> >& dirs
= mDirs
;
1878 const size_t N
= dirs
.size();
1879 for (size_t i
=0; i
<N
; i
++) {
1880 const sp
<AaptDir
>& d
= dirs
.itemAt(i
);
1881 if (d
->getLeaf() == name
) {
1889 valid_symbol_name(const String8
& symbol
)
1891 static char const * const KEYWORDS
[] = {
1892 "abstract", "assert", "boolean", "break",
1893 "byte", "case", "catch", "char", "class", "const", "continue",
1894 "default", "do", "double", "else", "enum", "extends", "final",
1895 "finally", "float", "for", "goto", "if", "implements", "import",
1896 "instanceof", "int", "interface", "long", "native", "new", "package",
1897 "private", "protected", "public", "return", "short", "static",
1898 "strictfp", "super", "switch", "synchronized", "this", "throw",
1899 "throws", "transient", "try", "void", "volatile", "while",
1900 "true", "false", "null",
1903 const char*const* k
= KEYWORDS
;
1904 const char*const s
= symbol
.string();
1906 if (0 == strcmp(s
, *k
)) {