]>
git.saurik.com Git - android/aapt.git/blob - AaptAssets.cpp
   2 // Copyright 2006 The Android Open Source Project 
   5 #include "AaptAssets.h" 
   8 #include <utils/misc.h> 
   9 #include <utils/SortedVector.h> 
  15 static const char* kDefaultLocale 
= "default"; 
  16 static const char* kWildcardName 
= "any"; 
  17 static const char* kAssetDir 
= "assets"; 
  18 static const char* kResourceDir 
= "res"; 
  19 static const char* kInvalidChars 
= "/\\:"; 
  20 static const size_t kMaxAssetFileName 
= 100; 
  22 static const String8 
kResString(kResourceDir
); 
  25  * Names of asset files must meet the following criteria: 
  27  *  - the filename length must be less than kMaxAssetFileName bytes long 
  28  *    (and can't be empty) 
  29  *  - all characters must be 7-bit printable ASCII 
  30  *  - none of { '/' '\\' ':' } 
  32  * Pass in just the filename, not the full path. 
  34 static bool validateFileName(const char* fileName
) 
  36     const char* cp 
= fileName
; 
  40         if ((*cp 
& 0x80) != 0) 
  41             return false;           // reject high ASCII 
  42         if (*cp 
< 0x20 || *cp 
>= 0x7f) 
  43             return false;           // reject control chars and 0x7f 
  44         if (strchr(kInvalidChars
, *cp
) != NULL
) 
  45             return false;           // reject path sep chars 
  50     if (len 
< 1 || len 
> kMaxAssetFileName
) 
  51         return false;               // reject empty or too long 
  56 static bool isHidden(const char *root
, const char *path
) 
  58     const char *type 
= NULL
; 
  60     // Skip all hidden files. 
  62         // Skip ., .. and  .svn but don't chatter about it. 
  63         if (strcmp(path
, ".") == 0 
  64             || strcmp(path
, "..") == 0 
  65             || strcmp(path
, ".svn") == 0) { 
  69     } else if (path
[0] == '_') { 
  70         // skip directories starting with _ (don't chatter about it) 
  71         String8 
subdirName(root
); 
  72         subdirName
.appendPath(path
); 
  73         if (getFileType(subdirName
.string()) == kFileTypeDirectory
) { 
  76     } else if (strcmp(path
, "CVS") == 0) { 
  77         // Skip CVS but don't chatter about it. 
  79     } else if (strcasecmp(path
, "thumbs.db") == 0 
  80                || strcasecmp(path
, "picasa.ini") == 0) { 
  81         // Skip suspected image indexes files. 
  83     } else if (path
[strlen(path
)-1] == '~') { 
  84         // Skip suspected emacs backup files. 
  87         // Let everything else through. 
  91     /* If we get this far, "type" should be set and the file 
  94     String8 
subdirName(root
); 
  95     subdirName
.appendPath(path
); 
  96     fprintf(stderr
, "    (skipping %s %s '%s')\n", type
, 
  97             getFileType(subdirName
.string())==kFileTypeDirectory 
? "dir":"file", 
 103 // ========================================================================= 
 104 // ========================================================================= 
 105 // ========================================================================= 
 108 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
) 
 110     ResTable_config config
; 
 113     if (getMccName(part
.string(), &config
)) { 
 120     if (getMncName(part
.string(), &config
)) { 
 127     if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) { 
 128         *axis 
= AXIS_LANGUAGE
; 
 129         *value 
= part
[1] << 8 | part
[0]; 
 133     // locale - language_REGION 
 134     if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1]) 
 135             && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) { 
 136         *axis 
= AXIS_LANGUAGE
; 
 137         *value 
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]); 
 142     if (getOrientationName(part
.string(), &config
)) { 
 143         *axis 
= AXIS_ORIENTATION
; 
 144         *value 
= config
.orientation
; 
 149     if (getDensityName(part
.string(), &config
)) { 
 150         *axis 
= AXIS_DENSITY
; 
 151         *value 
= config
.density
; 
 156     if (getTouchscreenName(part
.string(), &config
)) { 
 157         *axis 
= AXIS_TOUCHSCREEN
; 
 158         *value 
= config
.touchscreen
; 
 163     if (getKeysHiddenName(part
.string(), &config
)) { 
 164         *axis 
= AXIS_KEYSHIDDEN
; 
 165         *value 
= config
.inputFlags
; 
 170     if (getKeyboardName(part
.string(), &config
)) { 
 171         *axis 
= AXIS_KEYBOARD
; 
 172         *value 
= config
.keyboard
; 
 177     if (getNavigationName(part
.string(), &config
)) { 
 178         *axis 
= AXIS_NAVIGATION
; 
 179         *value 
= config
.navigation
; 
 184     if (getScreenSizeName(part
.string(), &config
)) { 
 185         *axis 
= AXIS_SCREENSIZE
; 
 186         *value 
= config
.screenSize
; 
 191     if (getScreenLayoutName(part
.string(), &config
)) { 
 192         *axis 
= AXIS_SCREENLAYOUT
; 
 193         *value 
= config
.screenLayout
; 
 198     if (getVersionName(part
.string(), &config
)) { 
 199         *axis 
= AXIS_VERSION
; 
 200         *value 
= config
.version
; 
 208 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
) 
 210     Vector
<String8
> parts
; 
 212     String8 mcc
, mnc
, loc
, orient
, den
, touch
, key
, keysHidden
, nav
, size
, layout
, vers
; 
 216     while (NULL 
!= (q 
= strchr(p
, '-'))) { 
 220         //printf("part: %s\n", parts[parts.size()-1].string()); 
 226     //printf("part: %s\n", parts[parts.size()-1].string()); 
 228     const int N 
= parts
.size(); 
 230     String8 part 
= parts
[index
]; 
 233     if (!isValidResourceType(part
)) { 
 245     if (getMccName(part
.string())) { 
 254         //printf("not mcc: %s\n", part.string()); 
 258     if (getMncName(part
.string())) { 
 267         //printf("not mcc: %s\n", part.string()); 
 271     if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) { 
 280         //printf("not language: %s\n", part.string()); 
 285             && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) { 
 288         loc 
+= part
.string() + 1; 
 296         //printf("not region: %s\n", part.string()); 
 300     if (getOrientationName(part
.string())) { 
 309         //printf("not orientation: %s\n", part.string()); 
 313     if (getDensityName(part
.string())) { 
 322         //printf("not density: %s\n", part.string()); 
 326     if (getTouchscreenName(part
.string())) { 
 335         //printf("not touchscreen: %s\n", part.string()); 
 339     if (getKeysHiddenName(part
.string())) { 
 348         //printf("not keysHidden: %s\n", part.string()); 
 352     if (getKeyboardName(part
.string())) { 
 361         //printf("not keyboard: %s\n", part.string()); 
 364     if (getNavigationName(part
.string())) { 
 373         //printf("not navigation: %s\n", part.string()); 
 376     if (getScreenSizeName(part
.string())) { 
 385         //printf("not screen size: %s\n", part.string()); 
 388     if (getScreenLayoutName(part
.string())) { 
 397         //printf("not screen layout: %s\n", part.string()); 
 400     if (getVersionName(part
.string())) { 
 409         //printf("not version: %s\n", part.string()); 
 412     // if there are extra parts, it doesn't match 
 419     this->orientation 
= orient
; 
 421     this->touchscreen 
= touch
; 
 422     this->keysHidden 
= keysHidden
; 
 423     this->keyboard 
= key
; 
 424     this->navigation 
= nav
; 
 425     this->screenSize 
= size
; 
 426     this->screenLayout 
= layout
; 
 427     this->version 
= vers
; 
 429     // what is this anyway? 
 436 AaptGroupEntry::toString() const 
 438     String8 s 
= this->mcc
; 
 444     s 
+= this->orientation
; 
 465 AaptGroupEntry::toDirName(const String8
& resType
) const 
 468     if (this->mcc 
!= "") { 
 472     if (this->mnc 
!= "") { 
 476     if (this->locale 
!= "") { 
 480     if (this->orientation 
!= "") { 
 484     if (this->density 
!= "") { 
 488     if (this->touchscreen 
!= "") { 
 492     if (this->keysHidden 
!= "") { 
 496     if (this->keyboard 
!= "") { 
 500     if (this->navigation 
!= "") { 
 504     if (this->screenSize 
!= "") { 
 508     if (this->screenLayout 
!= "") { 
 512     if (this->version 
!= "") { 
 520 bool AaptGroupEntry::getMccName(const char* name
, 
 521                                     ResTable_config
* out
) 
 523     if (strcmp(name
, kWildcardName
) == 0) { 
 524         if (out
) out
->mcc 
= 0; 
 527     const char* c 
= name
; 
 528     if (tolower(*c
) != 'm') return false; 
 530     if (tolower(*c
) != 'c') return false; 
 532     if (tolower(*c
) != 'c') return false; 
 537     while (*c 
>= '0' && *c 
<= '9') { 
 540     if (*c 
!= 0) return false; 
 541     if (c
-val 
!= 3) return false; 
 545         if (out
) out
->mcc 
= d
; 
 552 bool AaptGroupEntry::getMncName(const char* name
, 
 553                                     ResTable_config
* out
) 
 555     if (strcmp(name
, kWildcardName
) == 0) { 
 556         if (out
) out
->mcc 
= 0; 
 559     const char* c 
= name
; 
 560     if (tolower(*c
) != 'm') return false; 
 562     if (tolower(*c
) != 'n') return false; 
 564     if (tolower(*c
) != 'c') return false; 
 569     while (*c 
>= '0' && *c 
<= '9') { 
 572     if (*c 
!= 0) return false; 
 573     if (c
-val 
== 0 || c
-val 
> 3) return false; 
 577         if (out
) out
->mnc 
= d
; 
 585  * Does this directory name fit the pattern of a locale dir ("en-rUS" or 
 588  * TODO: Should insist that the first two letters are lower case, and the 
 589  * second two are upper. 
 591 bool AaptGroupEntry::getLocaleName(const char* fileName
, 
 592                                    ResTable_config
* out
) 
 594     if (strcmp(fileName
, kWildcardName
) == 0 
 595             || strcmp(fileName
, kDefaultLocale
) == 0) { 
 597             out
->language
[0] = 0; 
 598             out
->language
[1] = 0; 
 605     if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) { 
 607             out
->language
[0] = fileName
[0]; 
 608             out
->language
[1] = fileName
[1]; 
 615     if (strlen(fileName
) == 5 && 
 616         isalpha(fileName
[0]) && 
 617         isalpha(fileName
[1]) && 
 618         fileName
[2] == '-' && 
 619         isalpha(fileName
[3]) && 
 620         isalpha(fileName
[4])) { 
 622             out
->language
[0] = fileName
[0]; 
 623             out
->language
[1] = fileName
[1]; 
 624             out
->country
[0] = fileName
[3]; 
 625             out
->country
[1] = fileName
[4]; 
 633 bool AaptGroupEntry::getOrientationName(const char* name
, 
 634                                         ResTable_config
* out
) 
 636     if (strcmp(name
, kWildcardName
) == 0) { 
 637         if (out
) out
->orientation 
= out
->ORIENTATION_ANY
; 
 639     } else if (strcmp(name
, "port") == 0) { 
 640         if (out
) out
->orientation 
= out
->ORIENTATION_PORT
; 
 642     } else if (strcmp(name
, "land") == 0) { 
 643         if (out
) out
->orientation 
= out
->ORIENTATION_LAND
; 
 645     } else if (strcmp(name
, "square") == 0) { 
 646         if (out
) out
->orientation 
= out
->ORIENTATION_SQUARE
; 
 653 bool AaptGroupEntry::getDensityName(const char* name
, 
 654                                     ResTable_config
* out
) 
 656     if (strcmp(name
, kWildcardName
) == 0) { 
 657         if (out
) out
->density 
= ResTable_config::DENSITY_DEFAULT
; 
 661     if (strcmp(name
, "nodpi") == 0) { 
 662         if (out
) out
->density 
= ResTable_config::DENSITY_NONE
; 
 666     char* c 
= (char*)name
; 
 667     while (*c 
>= '0' && *c 
<= '9') { 
 671     // check that we have 'dpi' after the last digit. 
 672     if (toupper(c
[0]) != 'D' || 
 673             toupper(c
[1]) != 'P' || 
 674             toupper(c
[2]) != 'I' || 
 679     // temporarily replace the first letter with \0 to 
 688         if (out
) out
->density 
= d
; 
 695 bool AaptGroupEntry::getTouchscreenName(const char* name
, 
 696                                         ResTable_config
* out
) 
 698     if (strcmp(name
, kWildcardName
) == 0) { 
 699         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_ANY
; 
 701     } else if (strcmp(name
, "notouch") == 0) { 
 702         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_NOTOUCH
; 
 704     } else if (strcmp(name
, "stylus") == 0) { 
 705         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_STYLUS
; 
 707     } else if (strcmp(name
, "finger") == 0) { 
 708         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_FINGER
; 
 715 bool AaptGroupEntry::getKeysHiddenName(const char* name
, 
 716                                        ResTable_config
* out
) 
 720     if (strcmp(name
, kWildcardName
) == 0) { 
 721         mask 
= out
->MASK_KEYSHIDDEN
; 
 722         value 
= out
->KEYSHIDDEN_ANY
; 
 723     } else if (strcmp(name
, "keysexposed") == 0) { 
 724         mask 
= out
->MASK_KEYSHIDDEN
; 
 725         value 
= out
->KEYSHIDDEN_NO
; 
 726     } else if (strcmp(name
, "keyshidden") == 0) { 
 727         mask 
= out
->MASK_KEYSHIDDEN
; 
 728         value 
= out
->KEYSHIDDEN_YES
; 
 729     } else if (strcmp(name
, "keyssoft") == 0) { 
 730         mask 
= out
->MASK_KEYSHIDDEN
; 
 731         value 
= out
->KEYSHIDDEN_SOFT
; 
 735         if (out
) out
->inputFlags 
= (out
->inputFlags
&~mask
) | value
; 
 742 bool AaptGroupEntry::getKeyboardName(const char* name
, 
 743                                         ResTable_config
* out
) 
 745     if (strcmp(name
, kWildcardName
) == 0) { 
 746         if (out
) out
->keyboard 
= out
->KEYBOARD_ANY
; 
 748     } else if (strcmp(name
, "nokeys") == 0) { 
 749         if (out
) out
->keyboard 
= out
->KEYBOARD_NOKEYS
; 
 751     } else if (strcmp(name
, "qwerty") == 0) { 
 752         if (out
) out
->keyboard 
= out
->KEYBOARD_QWERTY
; 
 754     } else if (strcmp(name
, "12key") == 0) { 
 755         if (out
) out
->keyboard 
= out
->KEYBOARD_12KEY
; 
 762 bool AaptGroupEntry::getNavigationName(const char* name
, 
 763                                      ResTable_config
* out
) 
 765     if (strcmp(name
, kWildcardName
) == 0) { 
 766         if (out
) out
->navigation 
= out
->NAVIGATION_ANY
; 
 768     } else if (strcmp(name
, "nonav") == 0) { 
 769         if (out
) out
->navigation 
= out
->NAVIGATION_NONAV
; 
 771     } else if (strcmp(name
, "dpad") == 0) { 
 772         if (out
) out
->navigation 
= out
->NAVIGATION_DPAD
; 
 774     } else if (strcmp(name
, "trackball") == 0) { 
 775         if (out
) out
->navigation 
= out
->NAVIGATION_TRACKBALL
; 
 777     } else if (strcmp(name
, "wheel") == 0) { 
 778         if (out
) out
->navigation 
= out
->NAVIGATION_WHEEL
; 
 785 bool AaptGroupEntry::getScreenSizeName(const char* name
, 
 786                                        ResTable_config
* out
) 
 788     if (strcmp(name
, kWildcardName
) == 0) { 
 790             out
->screenWidth 
= out
->SCREENWIDTH_ANY
; 
 791             out
->screenHeight 
= out
->SCREENHEIGHT_ANY
; 
 796     const char* x 
= name
; 
 797     while (*x 
>= '0' && *x 
<= '9') x
++; 
 798     if (x 
== name 
|| *x 
!= 'x') return false; 
 799     String8 
xName(name
, x
-name
); 
 803     while (*y 
>= '0' && *y 
<= '9') y
++; 
 804     if (y 
== name 
|| *y 
!= 0) return false; 
 805     String8 
yName(x
, y
-x
); 
 807     uint16_t w 
= (uint16_t)atoi(xName
.string()); 
 808     uint16_t h 
= (uint16_t)atoi(yName
.string()); 
 814         out
->screenWidth 
= w
; 
 815         out
->screenHeight 
= h
; 
 821 bool AaptGroupEntry::getScreenLayoutName(const char* name
, 
 822                                      ResTable_config
* out
) 
 824     if (strcmp(name
, kWildcardName
) == 0) { 
 825         if (out
) out
->screenLayout 
= out
->SCREENLAYOUT_ANY
; 
 827     } else if (strcmp(name
, "smallscreen") == 0) { 
 828         if (out
) out
->screenLayout 
= out
->SCREENLAYOUT_SMALL
; 
 830     } else if (strcmp(name
, "normalscreen") == 0) { 
 831         if (out
) out
->screenLayout 
= out
->SCREENLAYOUT_NORMAL
; 
 833     } else if (strcmp(name
, "largescreen") == 0) { 
 834         if (out
) out
->screenLayout 
= out
->SCREENLAYOUT_LARGE
; 
 841 bool AaptGroupEntry::getVersionName(const char* name
, 
 842                                     ResTable_config
* out
) 
 844     if (strcmp(name
, kWildcardName
) == 0) { 
 846             out
->sdkVersion 
= out
->SDKVERSION_ANY
; 
 847             out
->minorVersion 
= out
->MINORVERSION_ANY
; 
 857     const char* s 
= name
; 
 858     while (*s 
>= '0' && *s 
<= '9') s
++; 
 859     if (s 
== name 
|| *s 
!= 0) return false; 
 860     String8 
sdkName(name
, s
-name
); 
 863         out
->sdkVersion 
= (uint16_t)atoi(sdkName
.string()); 
 864         out
->minorVersion 
= 0; 
 870 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const 
 872     int v 
= mcc
.compare(o
.mcc
); 
 873     if (v 
== 0) v 
= mnc
.compare(o
.mnc
); 
 874     if (v 
== 0) v 
= locale
.compare(o
.locale
); 
 875     if (v 
== 0) v 
= vendor
.compare(o
.vendor
); 
 876     if (v 
== 0) v 
= orientation
.compare(o
.orientation
); 
 877     if (v 
== 0) v 
= density
.compare(o
.density
); 
 878     if (v 
== 0) v 
= touchscreen
.compare(o
.touchscreen
); 
 879     if (v 
== 0) v 
= keysHidden
.compare(o
.keysHidden
); 
 880     if (v 
== 0) v 
= keyboard
.compare(o
.keyboard
); 
 881     if (v 
== 0) v 
= navigation
.compare(o
.navigation
); 
 882     if (v 
== 0) v 
= screenSize
.compare(o
.screenSize
); 
 883     if (v 
== 0) v 
= screenLayout
.compare(o
.screenLayout
); 
 884     if (v 
== 0) v 
= version
.compare(o
.version
); 
 888 ResTable_config 
AaptGroupEntry::toParams() const 
 890     ResTable_config params
; 
 891     memset(¶ms
, 0, sizeof(params
)); 
 892     getMccName(mcc
.string(), ¶ms
); 
 893     getMncName(mnc
.string(), ¶ms
); 
 894     getLocaleName(locale
.string(), ¶ms
); 
 895     getOrientationName(orientation
.string(), ¶ms
); 
 896     getDensityName(density
.string(), ¶ms
); 
 897     getTouchscreenName(touchscreen
.string(), ¶ms
); 
 898     getKeysHiddenName(keysHidden
.string(), ¶ms
); 
 899     getKeyboardName(keyboard
.string(), ¶ms
); 
 900     getNavigationName(navigation
.string(), ¶ms
); 
 901     getScreenSizeName(screenSize
.string(), ¶ms
); 
 902     getScreenLayoutName(screenLayout
.string(), ¶ms
); 
 903     getVersionName(version
.string(), ¶ms
); 
 907 // ========================================================================= 
 908 // ========================================================================= 
 909 // ========================================================================= 
 911 void* AaptFile::editData(size_t size
) 
 913     if (size 
<= mBufferSize
) { 
 917     size_t allocSize 
= (size
*3)/2; 
 918     void* buf 
= realloc(mData
, allocSize
); 
 924     mBufferSize 
= allocSize
; 
 928 void* AaptFile::editData(size_t* outSize
) 
 931         *outSize 
= mDataSize
; 
 936 void* AaptFile::padData(size_t wordSize
) 
 938     const size_t extra 
= mDataSize%wordSize
; 
 943     size_t initial 
= mDataSize
; 
 944     void* data 
= editData(initial
+(wordSize
-extra
)); 
 946         memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
); 
 951 status_t 
AaptFile::writeData(const void* data
, size_t size
) 
 953     size_t end 
= mDataSize
; 
 954     size_t total 
= size 
+ end
; 
 955     void* buf 
= editData(total
); 
 957         return UNKNOWN_ERROR
; 
 959     memcpy(((char*)buf
)+end
, data
, size
); 
 963 void AaptFile::clearData() 
 965     if (mData 
!= NULL
) free(mData
); 
 971 String8 
AaptFile::getPrintableSource() const 
 974         String8 
name(mGroupEntry
.locale
.string()); 
 975         name
.appendPath(mGroupEntry
.vendor
.string()); 
 976         name
.appendPath(mPath
); 
 977         name
.append(" #generated"); 
 983 // ========================================================================= 
 984 // ========================================================================= 
 985 // ========================================================================= 
 987 status_t 
AaptGroup::addFile(const sp
<AaptFile
>& file
) 
 989     if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) { 
 991         mFiles
.add(file
->getGroupEntry(), file
); 
 995     SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", 
 996                                                getPrintableSource().string()); 
 997     return UNKNOWN_ERROR
; 
1000 void AaptGroup::removeFile(size_t index
) 
1002         mFiles
.removeItemsAt(index
); 
1005 void AaptGroup::print() const 
1007     printf("  %s\n", getPath().string()); 
1008     const size_t N
=mFiles
.size(); 
1010     for (i
=0; i
<N
; i
++) { 
1011         sp
<AaptFile
> file 
= mFiles
.valueAt(i
); 
1012         const AaptGroupEntry
& e 
= file
->getGroupEntry(); 
1013         if (file
->hasData()) { 
1014             printf("      Gen: (%s) %d bytes\n", e
.toString().string(), 
1015                     (int)file
->getSize()); 
1017             printf("      Src: %s\n", file
->getPrintableSource().string()); 
1022 String8 
AaptGroup::getPrintableSource() const 
1024     if (mFiles
.size() > 0) { 
1025         // Arbitrarily pull the first source file out of the list. 
1026         return mFiles
.valueAt(0)->getPrintableSource(); 
1029     // Should never hit this case, but to be safe... 
1034 // ========================================================================= 
1035 // ========================================================================= 
1036 // ========================================================================= 
1038 status_t 
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
) 
1040     if (mFiles
.indexOfKey(name
) >= 0) { 
1041         return ALREADY_EXISTS
; 
1043     mFiles
.add(name
, file
); 
1047 status_t 
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
) 
1049     if (mDirs
.indexOfKey(name
) >= 0) { 
1050         return ALREADY_EXISTS
; 
1052     mDirs
.add(name
, dir
); 
1056 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
) 
1059     String8 remain 
= path
; 
1061     sp
<AaptDir
> subdir 
= this; 
1062     while (name 
= remain
.walkPath(&remain
), remain 
!= "") { 
1063         subdir 
= subdir
->makeDir(name
); 
1066     ssize_t i 
= subdir
->mDirs
.indexOfKey(name
); 
1068         return subdir
->mDirs
.valueAt(i
); 
1070     sp
<AaptDir
> dir 
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
)); 
1071     subdir
->mDirs
.add(name
, dir
); 
1075 void AaptDir::removeFile(const String8
& name
) 
1077     mFiles
.removeItem(name
); 
1080 void AaptDir::removeDir(const String8
& name
) 
1082     mDirs
.removeItem(name
); 
1085 status_t 
AaptDir::renameFile(const sp
<AaptFile
>& file
, const String8
& newName
) 
1087         sp
<AaptGroup
> origGroup
; 
1089         // Find and remove the given file with shear, brute force! 
1090         const size_t NG 
= mFiles
.size(); 
1092         for (i
=0; origGroup 
== NULL 
&& i
<NG
; i
++) { 
1093                 sp
<AaptGroup
> g 
= mFiles
.valueAt(i
); 
1094                 const size_t NF 
= g
->getFiles().size(); 
1095                 for (size_t j
=0; j
<NF
; j
++) { 
1096                         if (g
->getFiles().valueAt(j
) == file
) { 
1100                                         mFiles
.removeItemsAt(i
); 
1107         //printf("Renaming %s to %s\n", file->getPath().getPathName(), newName.string()); 
1109         // Place the file under its new name. 
1110         if (origGroup 
!= NULL
) { 
1111                 return addLeafFile(newName
, file
); 
1117 status_t 
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
) 
1119     sp
<AaptGroup
> group
; 
1120     if (mFiles
.indexOfKey(leafName
) >= 0) { 
1121         group 
= mFiles
.valueFor(leafName
); 
1123         group 
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
)); 
1124         mFiles
.add(leafName
, group
); 
1127     return group
->addFile(file
); 
1130 ssize_t 
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
, 
1131                             const AaptGroupEntry
& kind
, const String8
& resType
) 
1133     Vector
<String8
> fileNames
; 
1138         dir 
= opendir(srcDir
.string()); 
1140             fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
)); 
1141             return UNKNOWN_ERROR
; 
1145          * Slurp the filenames out of the directory. 
1148             struct dirent
* entry
; 
1150             entry 
= readdir(dir
); 
1154             if (isHidden(srcDir
.string(), entry
->d_name
)) 
1157             fileNames
.add(String8(entry
->d_name
)); 
1166      * Stash away the files and recursively descend into subdirectories. 
1168     const size_t N 
= fileNames
.size(); 
1170     for (i 
= 0; i 
< N
; i
++) { 
1171         String8 
pathName(srcDir
); 
1174         pathName
.appendPath(fileNames
[i
].string()); 
1175         type 
= getFileType(pathName
.string()); 
1176         if (type 
== kFileTypeDirectory
) { 
1178             bool notAdded 
= false; 
1179             if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) { 
1180                 subdir 
= mDirs
.valueFor(fileNames
[i
]); 
1182                 subdir 
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
])); 
1185             ssize_t res 
= subdir
->slurpFullTree(bundle
, pathName
, kind
, 
1187             if (res 
< NO_ERROR
) { 
1190             if (res 
> 0 && notAdded
) { 
1191                 mDirs
.add(fileNames
[i
], subdir
); 
1194         } else if (type 
== kFileTypeRegular
) { 
1195             sp
<AaptFile
> file 
= new AaptFile(pathName
, kind
, resType
); 
1196             status_t err 
= addLeafFile(fileNames
[i
], file
); 
1197             if (err 
!= NO_ERROR
) { 
1204             if (bundle
->getVerbose()) 
1205                 printf("   (ignoring non-file/dir '%s')\n", pathName
.string()); 
1212 status_t 
AaptDir::validate() const 
1214     const size_t NF 
= mFiles
.size(); 
1215     const size_t ND 
= mDirs
.size(); 
1217     for (i 
= 0; i 
< NF
; i
++) { 
1218         if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) { 
1219             SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error( 
1220                     "Invalid filename.  Unable to add."); 
1221             return UNKNOWN_ERROR
; 
1225         for (j 
= i
+1; j 
< NF
; j
++) { 
1226             if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(), 
1227                            mFiles
.valueAt(j
)->getLeaf().string()) == 0) { 
1228                 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error( 
1229                         "File is case-insensitive equivalent to: %s", 
1230                         mFiles
.valueAt(j
)->getPrintableSource().string()); 
1231                 return UNKNOWN_ERROR
; 
1234             // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" 
1235             // (this is mostly caught by the "marked" stuff, below) 
1238         for (j 
= 0; j 
< ND
; j
++) { 
1239             if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(), 
1240                            mDirs
.valueAt(j
)->getLeaf().string()) == 0) { 
1241                 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error( 
1242                         "File conflicts with dir from: %s", 
1243                         mDirs
.valueAt(j
)->getPrintableSource().string()); 
1244                 return UNKNOWN_ERROR
; 
1249     for (i 
= 0; i 
< ND
; i
++) { 
1250         if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) { 
1251             SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error( 
1252                     "Invalid directory name, unable to add."); 
1253             return UNKNOWN_ERROR
; 
1257         for (j 
= i
+1; j 
< ND
; j
++) { 
1258             if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(), 
1259                            mDirs
.valueAt(j
)->getLeaf().string()) == 0) { 
1260                 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error( 
1261                         "Directory is case-insensitive equivalent to: %s", 
1262                         mDirs
.valueAt(j
)->getPrintableSource().string()); 
1263                 return UNKNOWN_ERROR
; 
1267         status_t err 
= mDirs
.valueAt(i
)->validate(); 
1268         if (err 
!= NO_ERROR
) { 
1276 void AaptDir::print() const 
1278     const size_t ND
=getDirs().size(); 
1280     for (i
=0; i
<ND
; i
++) { 
1281         getDirs().valueAt(i
)->print(); 
1284     const size_t NF
=getFiles().size(); 
1285     for (i
=0; i
<NF
; i
++) { 
1286         getFiles().valueAt(i
)->print(); 
1290 String8 
AaptDir::getPrintableSource() const 
1292     if (mFiles
.size() > 0) { 
1293         // Arbitrarily pull the first file out of the list as the source dir. 
1294         return mFiles
.valueAt(0)->getPrintableSource().getPathDir(); 
1296     if (mDirs
.size() > 0) { 
1297         // Or arbitrarily pull the first dir out of the list as the source dir. 
1298         return mDirs
.valueAt(0)->getPrintableSource().getPathDir(); 
1301     // Should never hit this case, but to be safe... 
1306 // ========================================================================= 
1307 // ========================================================================= 
1308 // ========================================================================= 
1310 sp
<AaptFile
> AaptAssets::addFile( 
1311         const String8
& filePath
, const AaptGroupEntry
& entry
, 
1312         const String8
& srcDir
, sp
<AaptGroup
>* outGroup
, 
1313         const String8
& resType
) 
1315     sp
<AaptDir
> dir 
= this; 
1316     sp
<AaptGroup
> group
; 
1318     String8 root
, remain(filePath
), partialPath
; 
1319     while (remain
.length() > 0) { 
1320         root 
= remain
.walkPath(&remain
); 
1321         partialPath
.appendPath(root
); 
1323         const String8 
rootStr(root
); 
1325         if (remain
.length() == 0) { 
1326             ssize_t i 
= dir
->getFiles().indexOfKey(rootStr
); 
1328                 group 
= dir
->getFiles().valueAt(i
); 
1330                 group 
= new AaptGroup(rootStr
, filePath
); 
1331                 status_t res 
= dir
->addFile(rootStr
, group
); 
1332                 if (res 
!= NO_ERROR
) { 
1336             file 
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
); 
1337             status_t res 
= group
->addFile(file
); 
1338             if (res 
!= NO_ERROR
) { 
1344             ssize_t i 
= dir
->getDirs().indexOfKey(rootStr
); 
1346                 dir 
= dir
->getDirs().valueAt(i
); 
1348                 sp
<AaptDir
> subdir 
= new AaptDir(rootStr
, partialPath
); 
1349                 status_t res 
= dir
->addDir(rootStr
, subdir
); 
1350                 if (res 
!= NO_ERROR
) { 
1358     mGroupEntries
.add(entry
); 
1359     if (outGroup
) *outGroup 
= group
; 
1363 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
, 
1364                 const sp
<AaptFile
>& file
, const String8
& resType
) 
1366     sp
<AaptDir
> res 
= AaptDir::makeDir(kResString
); 
1367     String8 dirname 
= file
->getGroupEntry().toDirName(resType
); 
1368     sp
<AaptDir
> subdir 
= res
->makeDir(dirname
); 
1369     sp
<AaptGroup
> grr 
= new AaptGroup(leafName
, path
); 
1372     subdir
->addFile(leafName
, grr
); 
1376 ssize_t 
AaptAssets::slurpFromArgs(Bundle
* bundle
) 
1381     const Vector
<const char *>& resDirs 
= bundle
->getResourceSourceDirs(); 
1382     const size_t dirCount 
=resDirs
.size(); 
1383     sp
<AaptAssets
> current 
= this; 
1385     const int N 
= bundle
->getFileSpecCount(); 
1388      * If a package manifest was specified, include that first. 
1390     if (bundle
->getAndroidManifestFile() != NULL
) { 
1391         // place at root of zip. 
1392         String8 
srcFile(bundle
->getAndroidManifestFile()); 
1393         addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(), 
1399      * If a directory of custom assets was supplied, slurp 'em up. 
1401     if (bundle
->getAssetSourceDir()) { 
1402         const char* assetDir 
= bundle
->getAssetSourceDir(); 
1404         FileType type 
= getFileType(assetDir
); 
1405         if (type 
== kFileTypeNonexistent
) { 
1406             fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
); 
1407             return UNKNOWN_ERROR
; 
1409         if (type 
!= kFileTypeDirectory
) { 
1410             fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
); 
1411             return UNKNOWN_ERROR
; 
1414         String8 
assetRoot(assetDir
); 
1415         sp
<AaptDir
> assetAaptDir 
= makeDir(String8(kAssetDir
)); 
1416         AaptGroupEntry group
; 
1417         count 
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
, 
1424             mGroupEntries
.add(group
); 
1426         totalCount 
+= count
; 
1428         if (bundle
->getVerbose()) 
1429             printf("Found %d custom asset file%s in %s\n", 
1430                    count
, (count
==1) ? "" : "s", assetDir
); 
1434      * If a directory of resource-specific assets was supplied, slurp 'em up. 
1436     for (size_t i
=0; i
<dirCount
; i
++) { 
1437         const char *res 
= resDirs
[i
]; 
1439             type 
= getFileType(res
); 
1440             if (type 
== kFileTypeNonexistent
) { 
1441                 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
); 
1442                 return UNKNOWN_ERROR
; 
1444             if (type 
== kFileTypeDirectory
) { 
1446                     sp
<AaptAssets
> nextOverlay 
= new AaptAssets(); 
1447                     current
->setOverlay(nextOverlay
); 
1448                     current 
= nextOverlay
; 
1450                 count 
= current
->slurpResourceTree(bundle
, String8(res
)); 
1456                 totalCount 
+= count
; 
1459                 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
); 
1460                 return UNKNOWN_ERROR
; 
1466      * Now do any additional raw files. 
1468     for (int arg
=0; arg
<N
; arg
++) { 
1469         const char* assetDir 
= bundle
->getFileSpecEntry(arg
); 
1471         FileType type 
= getFileType(assetDir
); 
1472         if (type 
== kFileTypeNonexistent
) { 
1473             fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
); 
1474             return UNKNOWN_ERROR
; 
1476         if (type 
!= kFileTypeDirectory
) { 
1477             fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
); 
1478             return UNKNOWN_ERROR
; 
1481         String8 
assetRoot(assetDir
); 
1483         if (bundle
->getVerbose()) 
1484             printf("Processing raw dir '%s'\n", (const char*) assetDir
); 
1487          * Do a recursive traversal of subdir tree.  We don't make any 
1488          * guarantees about ordering, so we're okay with an inorder search 
1489          * using whatever order the OS happens to hand back to us. 
1491         count 
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8()); 
1493             /* failure; report error and remove archive */ 
1497         totalCount 
+= count
; 
1499         if (bundle
->getVerbose()) 
1500             printf("Found %d asset file%s in %s\n", 
1501                    count
, (count
==1) ? "" : "s", assetDir
); 
1505     if (count 
!= NO_ERROR
) { 
1515 ssize_t 
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
, 
1516                                     const AaptGroupEntry
& kind
, 
1517                                     const String8
& resType
) 
1519     ssize_t res 
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
); 
1521         mGroupEntries
.add(kind
); 
1527 ssize_t 
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
) 
1531     DIR* dir 
= opendir(srcDir
.string()); 
1533         fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
)); 
1534         return UNKNOWN_ERROR
; 
1540      * Run through the directory, looking for dirs that match the 
1544         struct dirent
* entry 
= readdir(dir
); 
1545         if (entry 
== NULL
) { 
1549         if (isHidden(srcDir
.string(), entry
->d_name
)) { 
1553         String8 
subdirName(srcDir
); 
1554         subdirName
.appendPath(entry
->d_name
); 
1556         AaptGroupEntry group
; 
1558         bool b 
= group
.initFromDirName(entry
->d_name
, &resType
); 
1560             fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(), 
1566         FileType type 
= getFileType(subdirName
.string()); 
1568         if (type 
== kFileTypeDirectory
) { 
1569             sp
<AaptDir
> dir 
= makeDir(String8(entry
->d_name
)); 
1570             ssize_t res 
= dir
->slurpFullTree(bundle
, subdirName
, group
, 
1577                 mGroupEntries
.add(group
); 
1583             if (bundle
->getVerbose()) { 
1584                 fprintf(stderr
, "   (ignoring file '%s')\n", subdirName
.string()); 
1600 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
) 
1603     SortedVector
<AaptGroupEntry
> entries
; 
1605     ZipFile
* zip 
= new ZipFile
; 
1606     status_t err 
= zip
->open(filename
, ZipFile::kOpenReadOnly
); 
1607     if (err 
!= NO_ERROR
) { 
1608         fprintf(stderr
, "error opening zip file %s\n", filename
); 
1614     const int N 
= zip
->getNumEntries(); 
1615     for (int i
=0; i
<N
; i
++) { 
1616         ZipEntry
* entry 
= zip
->getEntryByIndex(i
); 
1617         if (entry
->getDeleted()) { 
1621         String8 
entryName(entry
->getFileName()); 
1623         String8 dirName 
= entryName
.getPathDir(); 
1624         sp
<AaptDir
> dir 
= dirName 
== "" ? this : makeDir(dirName
); 
1627         AaptGroupEntry kind
; 
1630         if (entryName
.walkPath(&remain
) == kResourceDir
) { 
1631             // these are the resources, pull their type out of the directory name 
1632             kind
.initFromDirName(remain
.walkPath().string(), &resType
); 
1634             // these are untyped and don't have an AaptGroupEntry 
1636         if (entries
.indexOf(kind
) < 0) { 
1638             mGroupEntries
.add(kind
); 
1641         // use the one from the zip file if they both exist. 
1642         dir
->removeFile(entryName
.getPathLeaf()); 
1644         sp
<AaptFile
> file 
= new AaptFile(entryName
, kind
, resType
); 
1645         status_t err 
= dir
->addLeafFile(entryName
.getPathLeaf(), file
); 
1646         if (err 
!= NO_ERROR
) { 
1647             fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string()); 
1651         file
->setCompressionMethod(entry
->getCompressionMethod()); 
1654         if (entryName 
== "AndroidManifest.xml") { 
1655             printf("AndroidManifest.xml\n"); 
1657         printf("\n\nfile: %s\n", entryName
.string()); 
1660         size_t len 
= entry
->getUncompressedLen(); 
1661         void* data 
= zip
->uncompress(entry
); 
1662         void* buf 
= file
->editData(len
); 
1663         memcpy(buf
, data
, len
); 
1667         const unsigned char* p 
= (unsigned char*)data
; 
1668         const unsigned char* end 
= p
+len
; 
1670         for (int i
=0; i
<32 && p 
< end
; i
++) { 
1671             printf("0x%03x ", i
*0x10 + OFF
); 
1672             for (int j
=0; j
<0x10 && p 
< end
; j
++) { 
1673                 printf(" %02x", *p
); 
1690 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
) 
1692     sp
<AaptSymbols
> sym 
= mSymbols
.valueFor(name
); 
1694         sym 
= new AaptSymbols(); 
1695         mSymbols
.add(name
, sym
); 
1700 status_t 
AaptAssets::buildIncludedResources(Bundle
* bundle
) 
1702     if (!mHaveIncludedAssets
) { 
1703         // Add in all includes. 
1704         const Vector
<const char*>& incl 
= bundle
->getPackageIncludes(); 
1705         const size_t N
=incl
.size(); 
1706         for (size_t i
=0; i
<N
; i
++) { 
1707             if (bundle
->getVerbose()) 
1708                 printf("Including resources from package: %s\n", incl
[i
]); 
1709             if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) { 
1710                 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n", 
1712                 return UNKNOWN_ERROR
; 
1715         mHaveIncludedAssets 
= true; 
1721 status_t 
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
) 
1723     const ResTable
& res 
= getIncludedResources(); 
1725     return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
); 
1728 const ResTable
& AaptAssets::getIncludedResources() const 
1730     return mIncludedAssets
.getResources(false); 
1733 void AaptAssets::print() const 
1735     printf("Locale/Vendor pairs:\n"); 
1736     const size_t N
=mGroupEntries
.size(); 
1737     for (size_t i
=0; i
<N
; i
++) { 
1739                mGroupEntries
.itemAt(i
).locale
.string(), 
1740                mGroupEntries
.itemAt(i
).vendor
.string()); 
1743     printf("\nFiles:\n"); 
1748 valid_symbol_name(const String8
& symbol
) 
1750     static char const * const KEYWORDS
[] = { 
1751         "abstract", "assert", "boolean", "break", 
1752         "byte", "case", "catch", "char", "class", "const", "continue", 
1753         "default", "do", "double", "else", "enum", "extends", "final", 
1754         "finally", "float", "for", "goto", "if", "implements", "import", 
1755         "instanceof", "int", "interface", "long", "native", "new", "package", 
1756         "private", "protected", "public", "return", "short", "static", 
1757         "strictfp", "super", "switch", "synchronized", "this", "throw", 
1758         "throws", "transient", "try", "void", "volatile", "while", 
1759         "true", "false", "null", 
1762     const char*const* k 
= KEYWORDS
; 
1763     const char*const s 
= symbol
.string(); 
1765         if (0 == strcmp(s
, *k
)) {