2 // Copyright 2006 The Android Open Source Project 
   5 #include "AaptAssets.h" 
   6 #include "ResourceFilter.h" 
   9 #include <utils/misc.h> 
  10 #include <utils/SortedVector.h> 
  16 static const char* kDefaultLocale 
= "default"; 
  17 static const char* kWildcardName 
= "any"; 
  18 static const char* kAssetDir 
= "assets"; 
  19 static const char* kResourceDir 
= "res"; 
  20 static const char* kValuesDir 
= "values"; 
  21 static const char* kMipmapDir 
= "mipmap"; 
  22 static const char* kInvalidChars 
= "/\\:"; 
  23 static const size_t kMaxAssetFileName 
= 100; 
  25 static const String8 
kResString(kResourceDir
); 
  28  * Names of asset files must meet the following criteria: 
  30  *  - the filename length must be less than kMaxAssetFileName bytes long 
  31  *    (and can't be empty) 
  32  *  - all characters must be 7-bit printable ASCII 
  33  *  - none of { '/' '\\' ':' } 
  35  * Pass in just the filename, not the full path. 
  37 static bool validateFileName(const char* fileName
) 
  39     const char* cp 
= fileName
; 
  43         if ((*cp 
& 0x80) != 0) 
  44             return false;           // reject high ASCII 
  45         if (*cp 
< 0x20 || *cp 
>= 0x7f) 
  46             return false;           // reject control chars and 0x7f 
  47         if (strchr(kInvalidChars
, *cp
) != NULL
) 
  48             return false;           // reject path sep chars 
  53     if (len 
< 1 || len 
> kMaxAssetFileName
) 
  54         return false;               // reject empty or too long 
  59 static bool isHidden(const char *root
, const char *path
) 
  61     const char *ext  
= NULL
; 
  62     const char *type 
= NULL
; 
  64     // Skip all hidden files. 
  66         // Skip ., .. and  .svn but don't chatter about it. 
  67         if (strcmp(path
, ".") == 0 
  68             || strcmp(path
, "..") == 0 
  69             || strcmp(path
, ".svn") == 0) { 
  73     } else if (path
[0] == '_') { 
  74         // skip directories starting with _ (don't chatter about it) 
  75         String8 
subdirName(root
); 
  76         subdirName
.appendPath(path
); 
  77         if (getFileType(subdirName
.string()) == kFileTypeDirectory
) { 
  80     } else if (strcmp(path
, "CVS") == 0) { 
  81         // Skip CVS but don't chatter about it. 
  83     } else if (strcasecmp(path
, "thumbs.db") == 0 
  84                || strcasecmp(path
, "picasa.ini") == 0) { 
  85         // Skip suspected image indexes files. 
  87     } else if (path
[strlen(path
)-1] == '~') { 
  88         // Skip suspected emacs backup files. 
  90     } else if ((ext 
= strrchr(path
, '.')) != NULL 
&& strcmp(ext
, ".scc") == 0) { 
  91         // Skip VisualSourceSafe files and don't chatter about it 
  94         // Let everything else through. 
  98     /* If we get this far, "type" should be set and the file 
 101     String8 
subdirName(root
); 
 102     subdirName
.appendPath(path
); 
 103     fprintf(stderr
, "    (skipping %s %s '%s')\n", type
, 
 104             getFileType(subdirName
.string())==kFileTypeDirectory 
? "dir":"file", 
 105             subdirName
.string()); 
 110 // ========================================================================= 
 111 // ========================================================================= 
 112 // ========================================================================= 
 115 AaptGroupEntry::parseNamePart(const String8
& part
, int* axis
, uint32_t* value
) 
 117     ResTable_config config
; 
 120     if (getMccName(part
.string(), &config
)) { 
 127     if (getMncName(part
.string(), &config
)) { 
 134     if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) { 
 135         *axis 
= AXIS_LANGUAGE
; 
 136         *value 
= part
[1] << 8 | part
[0]; 
 140     // locale - language_REGION 
 141     if (part
.length() == 5 && isalpha(part
[0]) && isalpha(part
[1]) 
 142             && part
[2] == '_' && isalpha(part
[3]) && isalpha(part
[4])) { 
 143         *axis 
= AXIS_LANGUAGE
; 
 144         *value 
= (part
[4] << 24) | (part
[3] << 16) | (part
[1] << 8) | (part
[0]); 
 148     // smallest screen dp width 
 149     if (getSmallestScreenWidthDpName(part
.string(), &config
)) { 
 150         *axis 
= AXIS_SMALLESTSCREENWIDTHDP
; 
 151         *value 
= config
.smallestScreenWidthDp
; 
 156     if (getScreenWidthDpName(part
.string(), &config
)) { 
 157         *axis 
= AXIS_SCREENWIDTHDP
; 
 158         *value 
= config
.screenWidthDp
; 
 163     if (getScreenHeightDpName(part
.string(), &config
)) { 
 164         *axis 
= AXIS_SCREENHEIGHTDP
; 
 165         *value 
= config
.screenHeightDp
; 
 169     // screen layout size 
 170     if (getScreenLayoutSizeName(part
.string(), &config
)) { 
 171         *axis 
= AXIS_SCREENLAYOUTSIZE
; 
 172         *value 
= (config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
); 
 176     // screen layout long 
 177     if (getScreenLayoutLongName(part
.string(), &config
)) { 
 178         *axis 
= AXIS_SCREENLAYOUTLONG
; 
 179         *value 
= (config
.screenLayout
&ResTable_config::MASK_SCREENLONG
); 
 184     if (getOrientationName(part
.string(), &config
)) { 
 185         *axis 
= AXIS_ORIENTATION
; 
 186         *value 
= config
.orientation
; 
 191     if (getUiModeTypeName(part
.string(), &config
)) { 
 192         *axis 
= AXIS_UIMODETYPE
; 
 193         *value 
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
); 
 198     if (getUiModeNightName(part
.string(), &config
)) { 
 199         *axis 
= AXIS_UIMODENIGHT
; 
 200         *value 
= (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
); 
 205     if (getDensityName(part
.string(), &config
)) { 
 206         *axis 
= AXIS_DENSITY
; 
 207         *value 
= config
.density
; 
 212     if (getTouchscreenName(part
.string(), &config
)) { 
 213         *axis 
= AXIS_TOUCHSCREEN
; 
 214         *value 
= config
.touchscreen
; 
 219     if (getKeysHiddenName(part
.string(), &config
)) { 
 220         *axis 
= AXIS_KEYSHIDDEN
; 
 221         *value 
= config
.inputFlags
; 
 226     if (getKeyboardName(part
.string(), &config
)) { 
 227         *axis 
= AXIS_KEYBOARD
; 
 228         *value 
= config
.keyboard
; 
 233     if (getNavHiddenName(part
.string(), &config
)) { 
 234         *axis 
= AXIS_NAVHIDDEN
; 
 235         *value 
= config
.inputFlags
; 
 240     if (getNavigationName(part
.string(), &config
)) { 
 241         *axis 
= AXIS_NAVIGATION
; 
 242         *value 
= config
.navigation
; 
 247     if (getScreenSizeName(part
.string(), &config
)) { 
 248         *axis 
= AXIS_SCREENSIZE
; 
 249         *value 
= config
.screenSize
; 
 254     if (getVersionName(part
.string(), &config
)) { 
 255         *axis 
= AXIS_VERSION
; 
 256         *value 
= config
.version
; 
 264 AaptGroupEntry::getConfigValueForAxis(const ResTable_config
& config
, int axis
) 
 272             return (((uint32_t)config
.country
[1]) << 24) | (((uint32_t)config
.country
[0]) << 16) 
 273                 | (((uint32_t)config
.language
[1]) << 8) | (config
.language
[0]); 
 274         case AXIS_SCREENLAYOUTSIZE
: 
 275             return config
.screenLayout
&ResTable_config::MASK_SCREENSIZE
; 
 276         case AXIS_ORIENTATION
: 
 277             return config
.orientation
; 
 278         case AXIS_UIMODETYPE
: 
 279             return (config
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
); 
 280         case AXIS_UIMODENIGHT
: 
 281             return (config
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
); 
 283             return config
.density
; 
 284         case AXIS_TOUCHSCREEN
: 
 285             return config
.touchscreen
; 
 286         case AXIS_KEYSHIDDEN
: 
 287             return config
.inputFlags
; 
 289             return config
.keyboard
; 
 290         case AXIS_NAVIGATION
: 
 291             return config
.navigation
; 
 292         case AXIS_SCREENSIZE
: 
 293             return config
.screenSize
; 
 294         case AXIS_SMALLESTSCREENWIDTHDP
: 
 295             return config
.smallestScreenWidthDp
; 
 296         case AXIS_SCREENWIDTHDP
: 
 297             return config
.screenWidthDp
; 
 298         case AXIS_SCREENHEIGHTDP
: 
 299             return config
.screenHeightDp
; 
 301             return config
.version
; 
 307 AaptGroupEntry::configSameExcept(const ResTable_config
& config
, 
 308         const ResTable_config
& otherConfig
, int axis
) 
 310     for (int i
=AXIS_START
; i
<=AXIS_END
; i
++) { 
 314         if (getConfigValueForAxis(config
, i
) != getConfigValueForAxis(otherConfig
, i
)) { 
 322 AaptGroupEntry::initFromDirName(const char* dir
, String8
* resType
) 
 324     mParamsChanged 
= true; 
 326     Vector
<String8
> parts
; 
 328     String8 mcc
, mnc
, loc
, layoutsize
, layoutlong
, orient
, den
; 
 329     String8 touch
, key
, keysHidden
, nav
, navHidden
, size
, vers
; 
 330     String8 uiModeType
, uiModeNight
, smallestwidthdp
, widthdp
, heightdp
; 
 334     while (NULL 
!= (q 
= strchr(p
, '-'))) { 
 338         //printf("part: %s\n", parts[parts.size()-1].string()); 
 344     //printf("part: %s\n", parts[parts.size()-1].string()); 
 346     const int N 
= parts
.size(); 
 348     String8 part 
= parts
[index
]; 
 351     if (!isValidResourceType(part
)) { 
 363     if (getMccName(part
.string())) { 
 372         //printf("not mcc: %s\n", part.string()); 
 376     if (getMncName(part
.string())) { 
 385         //printf("not mcc: %s\n", part.string()); 
 389     if (part
.length() == 2 && isalpha(part
[0]) && isalpha(part
[1])) { 
 398         //printf("not language: %s\n", part.string()); 
 403             && part
.length() == 3 && part
[0] == 'r' && part
[0] && part
[1]) { 
 406         loc 
+= part
.string() + 1; 
 414         //printf("not region: %s\n", part.string()); 
 417     if (getSmallestScreenWidthDpName(part
.string())) { 
 418         smallestwidthdp 
= part
; 
 426         //printf("not smallest screen width dp: %s\n", part.string()); 
 429     if (getScreenWidthDpName(part
.string())) { 
 438         //printf("not screen width dp: %s\n", part.string()); 
 441     if (getScreenHeightDpName(part
.string())) { 
 450         //printf("not screen height dp: %s\n", part.string()); 
 453     if (getScreenLayoutSizeName(part
.string())) { 
 462         //printf("not screen layout size: %s\n", part.string()); 
 465     if (getScreenLayoutLongName(part
.string())) { 
 474         //printf("not screen layout long: %s\n", part.string()); 
 478     if (getOrientationName(part
.string())) { 
 487         //printf("not orientation: %s\n", part.string()); 
 491     if (getUiModeTypeName(part
.string())) { 
 500         //printf("not ui mode type: %s\n", part.string()); 
 504     if (getUiModeNightName(part
.string())) { 
 513         //printf("not ui mode night: %s\n", part.string()); 
 517     if (getDensityName(part
.string())) { 
 526         //printf("not density: %s\n", part.string()); 
 530     if (getTouchscreenName(part
.string())) { 
 539         //printf("not touchscreen: %s\n", part.string()); 
 543     if (getKeysHiddenName(part
.string())) { 
 552         //printf("not keysHidden: %s\n", part.string()); 
 556     if (getKeyboardName(part
.string())) { 
 565         //printf("not keyboard: %s\n", part.string()); 
 569     if (getNavHiddenName(part
.string())) { 
 578         //printf("not navHidden: %s\n", part.string()); 
 581     if (getNavigationName(part
.string())) { 
 590         //printf("not navigation: %s\n", part.string()); 
 593     if (getScreenSizeName(part
.string())) { 
 602         //printf("not screen size: %s\n", part.string()); 
 605     if (getVersionName(part
.string())) { 
 614         //printf("not version: %s\n", part.string()); 
 617     // if there are extra parts, it doesn't match 
 624     this->screenLayoutSize 
= layoutsize
; 
 625     this->screenLayoutLong 
= layoutlong
; 
 626     this->smallestScreenWidthDp 
= smallestwidthdp
; 
 627     this->screenWidthDp 
= widthdp
; 
 628     this->screenHeightDp 
= heightdp
; 
 629     this->orientation 
= orient
; 
 630     this->uiModeType 
= uiModeType
; 
 631     this->uiModeNight 
= uiModeNight
; 
 633     this->touchscreen 
= touch
; 
 634     this->keysHidden 
= keysHidden
; 
 635     this->keyboard 
= key
; 
 636     this->navHidden 
= navHidden
; 
 637     this->navigation 
= nav
; 
 638     this->screenSize 
= size
; 
 639     this->version 
= vers
; 
 641     // what is this anyway? 
 648 AaptGroupEntry::toString() const 
 650     String8 s 
= this->mcc
; 
 656     s 
+= smallestScreenWidthDp
; 
 662     s 
+= screenLayoutSize
; 
 664     s 
+= screenLayoutLong
; 
 666     s 
+= this->orientation
; 
 691 AaptGroupEntry::toDirName(const String8
& resType
) const 
 694     if (this->mcc 
!= "") { 
 695         if (s
.length() > 0) { 
 700     if (this->mnc 
!= "") { 
 701         if (s
.length() > 0) { 
 706     if (this->locale 
!= "") { 
 707         if (s
.length() > 0) { 
 712     if (this->smallestScreenWidthDp 
!= "") { 
 713         if (s
.length() > 0) { 
 716         s 
+= smallestScreenWidthDp
; 
 718     if (this->screenWidthDp 
!= "") { 
 719         if (s
.length() > 0) { 
 724     if (this->screenHeightDp 
!= "") { 
 725         if (s
.length() > 0) { 
 730     if (this->screenLayoutSize 
!= "") { 
 731         if (s
.length() > 0) { 
 734         s 
+= screenLayoutSize
; 
 736     if (this->screenLayoutLong 
!= "") { 
 737         if (s
.length() > 0) { 
 740         s 
+= screenLayoutLong
; 
 742     if (this->orientation 
!= "") { 
 743         if (s
.length() > 0) { 
 748     if (this->uiModeType 
!= "") { 
 749         if (s
.length() > 0) { 
 754     if (this->uiModeNight 
!= "") { 
 755         if (s
.length() > 0) { 
 760     if (this->density 
!= "") { 
 761         if (s
.length() > 0) { 
 766     if (this->touchscreen 
!= "") { 
 767         if (s
.length() > 0) { 
 772     if (this->keysHidden 
!= "") { 
 773         if (s
.length() > 0) { 
 778     if (this->keyboard 
!= "") { 
 779         if (s
.length() > 0) { 
 784     if (this->navHidden 
!= "") { 
 785         if (s
.length() > 0) { 
 790     if (this->navigation 
!= "") { 
 791         if (s
.length() > 0) { 
 796     if (this->screenSize 
!= "") { 
 797         if (s
.length() > 0) { 
 802     if (this->version 
!= "") { 
 803         if (s
.length() > 0) { 
 812 bool AaptGroupEntry::getMccName(const char* name
, 
 813                                     ResTable_config
* out
) 
 815     if (strcmp(name
, kWildcardName
) == 0) { 
 816         if (out
) out
->mcc 
= 0; 
 819     const char* c 
= name
; 
 820     if (tolower(*c
) != 'm') return false; 
 822     if (tolower(*c
) != 'c') return false; 
 824     if (tolower(*c
) != 'c') return false; 
 829     while (*c 
>= '0' && *c 
<= '9') { 
 832     if (*c 
!= 0) return false; 
 833     if (c
-val 
!= 3) return false; 
 837         if (out
) out
->mcc 
= d
; 
 844 bool AaptGroupEntry::getMncName(const char* name
, 
 845                                     ResTable_config
* out
) 
 847     if (strcmp(name
, kWildcardName
) == 0) { 
 848         if (out
) out
->mcc 
= 0; 
 851     const char* c 
= name
; 
 852     if (tolower(*c
) != 'm') return false; 
 854     if (tolower(*c
) != 'n') return false; 
 856     if (tolower(*c
) != 'c') return false; 
 861     while (*c 
>= '0' && *c 
<= '9') { 
 864     if (*c 
!= 0) return false; 
 865     if (c
-val 
== 0 || c
-val 
> 3) return false; 
 868         out
->mnc 
= atoi(val
); 
 875  * Does this directory name fit the pattern of a locale dir ("en-rUS" or 
 878  * TODO: Should insist that the first two letters are lower case, and the 
 879  * second two are upper. 
 881 bool AaptGroupEntry::getLocaleName(const char* fileName
, 
 882                                    ResTable_config
* out
) 
 884     if (strcmp(fileName
, kWildcardName
) == 0 
 885             || strcmp(fileName
, kDefaultLocale
) == 0) { 
 887             out
->language
[0] = 0; 
 888             out
->language
[1] = 0; 
 895     if (strlen(fileName
) == 2 && isalpha(fileName
[0]) && isalpha(fileName
[1])) { 
 897             out
->language
[0] = fileName
[0]; 
 898             out
->language
[1] = fileName
[1]; 
 905     if (strlen(fileName
) == 5 && 
 906         isalpha(fileName
[0]) && 
 907         isalpha(fileName
[1]) && 
 908         fileName
[2] == '-' && 
 909         isalpha(fileName
[3]) && 
 910         isalpha(fileName
[4])) { 
 912             out
->language
[0] = fileName
[0]; 
 913             out
->language
[1] = fileName
[1]; 
 914             out
->country
[0] = fileName
[3]; 
 915             out
->country
[1] = fileName
[4]; 
 923 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name
, 
 924                                      ResTable_config
* out
) 
 926     if (strcmp(name
, kWildcardName
) == 0) { 
 927         if (out
) out
->screenLayout 
= 
 928                 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
) 
 929                 | ResTable_config::SCREENSIZE_ANY
; 
 931     } else if (strcmp(name
, "small") == 0) { 
 932         if (out
) out
->screenLayout 
= 
 933                 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
) 
 934                 | ResTable_config::SCREENSIZE_SMALL
; 
 936     } else if (strcmp(name
, "normal") == 0) { 
 937         if (out
) out
->screenLayout 
= 
 938                 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
) 
 939                 | ResTable_config::SCREENSIZE_NORMAL
; 
 941     } else if (strcmp(name
, "large") == 0) { 
 942         if (out
) out
->screenLayout 
= 
 943                 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
) 
 944                 | ResTable_config::SCREENSIZE_LARGE
; 
 946     } else if (strcmp(name
, "xlarge") == 0) { 
 947         if (out
) out
->screenLayout 
= 
 948                 (out
->screenLayout
&~ResTable_config::MASK_SCREENSIZE
) 
 949                 | ResTable_config::SCREENSIZE_XLARGE
; 
 956 bool AaptGroupEntry::getScreenLayoutLongName(const char* name
, 
 957                                      ResTable_config
* out
) 
 959     if (strcmp(name
, kWildcardName
) == 0) { 
 960         if (out
) out
->screenLayout 
= 
 961                 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
) 
 962                 | ResTable_config::SCREENLONG_ANY
; 
 964     } else if (strcmp(name
, "long") == 0) { 
 965         if (out
) out
->screenLayout 
= 
 966                 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
) 
 967                 | ResTable_config::SCREENLONG_YES
; 
 969     } else if (strcmp(name
, "notlong") == 0) { 
 970         if (out
) out
->screenLayout 
= 
 971                 (out
->screenLayout
&~ResTable_config::MASK_SCREENLONG
) 
 972                 | ResTable_config::SCREENLONG_NO
; 
 979 bool AaptGroupEntry::getOrientationName(const char* name
, 
 980                                         ResTable_config
* out
) 
 982     if (strcmp(name
, kWildcardName
) == 0) { 
 983         if (out
) out
->orientation 
= out
->ORIENTATION_ANY
; 
 985     } else if (strcmp(name
, "port") == 0) { 
 986         if (out
) out
->orientation 
= out
->ORIENTATION_PORT
; 
 988     } else if (strcmp(name
, "land") == 0) { 
 989         if (out
) out
->orientation 
= out
->ORIENTATION_LAND
; 
 991     } else if (strcmp(name
, "square") == 0) { 
 992         if (out
) out
->orientation 
= out
->ORIENTATION_SQUARE
; 
 999 bool AaptGroupEntry::getUiModeTypeName(const char* name
, 
1000                                        ResTable_config
* out
) 
1002     if (strcmp(name
, kWildcardName
) == 0) { 
1003         if (out
) out
->uiMode 
= 
1004                 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
) 
1005                 | ResTable_config::UI_MODE_TYPE_ANY
; 
1007     } else if (strcmp(name
, "desk") == 0) { 
1008       if (out
) out
->uiMode 
= 
1009               (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
) 
1010               | ResTable_config::UI_MODE_TYPE_DESK
; 
1012     } else if (strcmp(name
, "car") == 0) { 
1013       if (out
) out
->uiMode 
= 
1014               (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
) 
1015               | ResTable_config::UI_MODE_TYPE_CAR
; 
1017     } else if (strcmp(name
, "television") == 0) { 
1018       if (out
) out
->uiMode 
= 
1019               (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
) 
1020               | ResTable_config::UI_MODE_TYPE_TELEVISION
; 
1022     } else if (strcmp(name
, "appliance") == 0) { 
1023       if (out
) out
->uiMode 
= 
1024               (out
->uiMode
&~ResTable_config::MASK_UI_MODE_TYPE
) 
1025               | ResTable_config::UI_MODE_TYPE_APPLIANCE
; 
1032 bool AaptGroupEntry::getUiModeNightName(const char* name
, 
1033                                           ResTable_config
* out
) 
1035     if (strcmp(name
, kWildcardName
) == 0) { 
1036         if (out
) out
->uiMode 
= 
1037                 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
) 
1038                 | ResTable_config::UI_MODE_NIGHT_ANY
; 
1040     } else if (strcmp(name
, "night") == 0) { 
1041         if (out
) out
->uiMode 
= 
1042                 (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
) 
1043                 | ResTable_config::UI_MODE_NIGHT_YES
; 
1045     } else if (strcmp(name
, "notnight") == 0) { 
1046       if (out
) out
->uiMode 
= 
1047               (out
->uiMode
&~ResTable_config::MASK_UI_MODE_NIGHT
) 
1048               | ResTable_config::UI_MODE_NIGHT_NO
; 
1055 bool AaptGroupEntry::getDensityName(const char* name
, 
1056                                     ResTable_config
* out
) 
1058     if (strcmp(name
, kWildcardName
) == 0) { 
1059         if (out
) out
->density 
= ResTable_config::DENSITY_DEFAULT
; 
1063     if (strcmp(name
, "nodpi") == 0) { 
1064         if (out
) out
->density 
= ResTable_config::DENSITY_NONE
; 
1068     if (strcmp(name
, "ldpi") == 0) { 
1069         if (out
) out
->density 
= ResTable_config::DENSITY_LOW
; 
1073     if (strcmp(name
, "mdpi") == 0) { 
1074         if (out
) out
->density 
= ResTable_config::DENSITY_MEDIUM
; 
1078     if (strcmp(name
, "tvdpi") == 0) { 
1079         if (out
) out
->density 
= ResTable_config::DENSITY_TV
; 
1083     if (strcmp(name
, "hdpi") == 0) { 
1084         if (out
) out
->density 
= ResTable_config::DENSITY_HIGH
; 
1088     if (strcmp(name
, "xhdpi") == 0) { 
1089         if (out
) out
->density 
= ResTable_config::DENSITY_MEDIUM
*2; 
1093     char* c 
= (char*)name
; 
1094     while (*c 
>= '0' && *c 
<= '9') { 
1098     // check that we have 'dpi' after the last digit. 
1099     if (toupper(c
[0]) != 'D' || 
1100             toupper(c
[1]) != 'P' || 
1101             toupper(c
[2]) != 'I' || 
1106     // temporarily replace the first letter with \0 to 
1115         if (out
) out
->density 
= d
; 
1122 bool AaptGroupEntry::getTouchscreenName(const char* name
, 
1123                                         ResTable_config
* out
) 
1125     if (strcmp(name
, kWildcardName
) == 0) { 
1126         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_ANY
; 
1128     } else if (strcmp(name
, "notouch") == 0) { 
1129         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_NOTOUCH
; 
1131     } else if (strcmp(name
, "stylus") == 0) { 
1132         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_STYLUS
; 
1134     } else if (strcmp(name
, "finger") == 0) { 
1135         if (out
) out
->touchscreen 
= out
->TOUCHSCREEN_FINGER
; 
1142 bool AaptGroupEntry::getKeysHiddenName(const char* name
, 
1143                                        ResTable_config
* out
) 
1147     if (strcmp(name
, kWildcardName
) == 0) { 
1148         mask 
= ResTable_config::MASK_KEYSHIDDEN
; 
1149         value 
= ResTable_config::KEYSHIDDEN_ANY
; 
1150     } else if (strcmp(name
, "keysexposed") == 0) { 
1151         mask 
= ResTable_config::MASK_KEYSHIDDEN
; 
1152         value 
= ResTable_config::KEYSHIDDEN_NO
; 
1153     } else if (strcmp(name
, "keyshidden") == 0) { 
1154         mask 
= ResTable_config::MASK_KEYSHIDDEN
; 
1155         value 
= ResTable_config::KEYSHIDDEN_YES
; 
1156     } else if (strcmp(name
, "keyssoft") == 0) { 
1157         mask 
= ResTable_config::MASK_KEYSHIDDEN
; 
1158         value 
= ResTable_config::KEYSHIDDEN_SOFT
; 
1162         if (out
) out
->inputFlags 
= (out
->inputFlags
&~mask
) | value
; 
1169 bool AaptGroupEntry::getKeyboardName(const char* name
, 
1170                                         ResTable_config
* out
) 
1172     if (strcmp(name
, kWildcardName
) == 0) { 
1173         if (out
) out
->keyboard 
= out
->KEYBOARD_ANY
; 
1175     } else if (strcmp(name
, "nokeys") == 0) { 
1176         if (out
) out
->keyboard 
= out
->KEYBOARD_NOKEYS
; 
1178     } else if (strcmp(name
, "qwerty") == 0) { 
1179         if (out
) out
->keyboard 
= out
->KEYBOARD_QWERTY
; 
1181     } else if (strcmp(name
, "12key") == 0) { 
1182         if (out
) out
->keyboard 
= out
->KEYBOARD_12KEY
; 
1189 bool AaptGroupEntry::getNavHiddenName(const char* name
, 
1190                                        ResTable_config
* out
) 
1194     if (strcmp(name
, kWildcardName
) == 0) { 
1195         mask 
= ResTable_config::MASK_NAVHIDDEN
; 
1196         value 
= ResTable_config::NAVHIDDEN_ANY
; 
1197     } else if (strcmp(name
, "navexposed") == 0) { 
1198         mask 
= ResTable_config::MASK_NAVHIDDEN
; 
1199         value 
= ResTable_config::NAVHIDDEN_NO
; 
1200     } else if (strcmp(name
, "navhidden") == 0) { 
1201         mask 
= ResTable_config::MASK_NAVHIDDEN
; 
1202         value 
= ResTable_config::NAVHIDDEN_YES
; 
1206         if (out
) out
->inputFlags 
= (out
->inputFlags
&~mask
) | value
; 
1213 bool AaptGroupEntry::getNavigationName(const char* name
, 
1214                                      ResTable_config
* out
) 
1216     if (strcmp(name
, kWildcardName
) == 0) { 
1217         if (out
) out
->navigation 
= out
->NAVIGATION_ANY
; 
1219     } else if (strcmp(name
, "nonav") == 0) { 
1220         if (out
) out
->navigation 
= out
->NAVIGATION_NONAV
; 
1222     } else if (strcmp(name
, "dpad") == 0) { 
1223         if (out
) out
->navigation 
= out
->NAVIGATION_DPAD
; 
1225     } else if (strcmp(name
, "trackball") == 0) { 
1226         if (out
) out
->navigation 
= out
->NAVIGATION_TRACKBALL
; 
1228     } else if (strcmp(name
, "wheel") == 0) { 
1229         if (out
) out
->navigation 
= out
->NAVIGATION_WHEEL
; 
1236 bool AaptGroupEntry::getScreenSizeName(const char* name
, ResTable_config
* out
) 
1238     if (strcmp(name
, kWildcardName
) == 0) { 
1240             out
->screenWidth 
= out
->SCREENWIDTH_ANY
; 
1241             out
->screenHeight 
= out
->SCREENHEIGHT_ANY
; 
1246     const char* x 
= name
; 
1247     while (*x 
>= '0' && *x 
<= '9') x
++; 
1248     if (x 
== name 
|| *x 
!= 'x') return false; 
1249     String8 
xName(name
, x
-name
); 
1253     while (*y 
>= '0' && *y 
<= '9') y
++; 
1254     if (y 
== name 
|| *y 
!= 0) return false; 
1255     String8 
yName(x
, y
-x
); 
1257     uint16_t w 
= (uint16_t)atoi(xName
.string()); 
1258     uint16_t h 
= (uint16_t)atoi(yName
.string()); 
1264         out
->screenWidth 
= w
; 
1265         out
->screenHeight 
= h
; 
1271 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name
, ResTable_config
* out
) 
1273     if (strcmp(name
, kWildcardName
) == 0) { 
1275             out
->smallestScreenWidthDp 
= out
->SCREENWIDTH_ANY
; 
1280     if (*name 
!= 's') return false; 
1282     if (*name 
!= 'w') return false; 
1284     const char* x 
= name
; 
1285     while (*x 
>= '0' && *x 
<= '9') x
++; 
1286     if (x 
== name 
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false; 
1287     String8 
xName(name
, x
-name
); 
1290         out
->smallestScreenWidthDp 
= (uint16_t)atoi(xName
.string()); 
1296 bool AaptGroupEntry::getScreenWidthDpName(const char* name
, ResTable_config
* out
) 
1298     if (strcmp(name
, kWildcardName
) == 0) { 
1300             out
->screenWidthDp 
= out
->SCREENWIDTH_ANY
; 
1305     if (*name 
!= 'w') return false; 
1307     const char* x 
= name
; 
1308     while (*x 
>= '0' && *x 
<= '9') x
++; 
1309     if (x 
== name 
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false; 
1310     String8 
xName(name
, x
-name
); 
1313         out
->screenWidthDp 
= (uint16_t)atoi(xName
.string()); 
1319 bool AaptGroupEntry::getScreenHeightDpName(const char* name
, ResTable_config
* out
) 
1321     if (strcmp(name
, kWildcardName
) == 0) { 
1323             out
->screenHeightDp 
= out
->SCREENWIDTH_ANY
; 
1328     if (*name 
!= 'h') return false; 
1330     const char* x 
= name
; 
1331     while (*x 
>= '0' && *x 
<= '9') x
++; 
1332     if (x 
== name 
|| x
[0] != 'd' || x
[1] != 'p' || x
[2] != 0) return false; 
1333     String8 
xName(name
, x
-name
); 
1336         out
->screenHeightDp 
= (uint16_t)atoi(xName
.string()); 
1342 bool AaptGroupEntry::getVersionName(const char* name
, ResTable_config
* out
) 
1344     if (strcmp(name
, kWildcardName
) == 0) { 
1346             out
->sdkVersion 
= out
->SDKVERSION_ANY
; 
1347             out
->minorVersion 
= out
->MINORVERSION_ANY
; 
1357     const char* s 
= name
; 
1358     while (*s 
>= '0' && *s 
<= '9') s
++; 
1359     if (s 
== name 
|| *s 
!= 0) return false; 
1360     String8 
sdkName(name
, s
-name
); 
1363         out
->sdkVersion 
= (uint16_t)atoi(sdkName
.string()); 
1364         out
->minorVersion 
= 0; 
1370 int AaptGroupEntry::compare(const AaptGroupEntry
& o
) const 
1372     int v 
= mcc
.compare(o
.mcc
); 
1373     if (v 
== 0) v 
= mnc
.compare(o
.mnc
); 
1374     if (v 
== 0) v 
= locale
.compare(o
.locale
); 
1375     if (v 
== 0) v 
= vendor
.compare(o
.vendor
); 
1376     if (v 
== 0) v 
= smallestScreenWidthDp
.compare(o
.smallestScreenWidthDp
); 
1377     if (v 
== 0) v 
= screenWidthDp
.compare(o
.screenWidthDp
); 
1378     if (v 
== 0) v 
= screenHeightDp
.compare(o
.screenHeightDp
); 
1379     if (v 
== 0) v 
= screenLayoutSize
.compare(o
.screenLayoutSize
); 
1380     if (v 
== 0) v 
= screenLayoutLong
.compare(o
.screenLayoutLong
); 
1381     if (v 
== 0) v 
= orientation
.compare(o
.orientation
); 
1382     if (v 
== 0) v 
= uiModeType
.compare(o
.uiModeType
); 
1383     if (v 
== 0) v 
= uiModeNight
.compare(o
.uiModeNight
); 
1384     if (v 
== 0) v 
= density
.compare(o
.density
); 
1385     if (v 
== 0) v 
= touchscreen
.compare(o
.touchscreen
); 
1386     if (v 
== 0) v 
= keysHidden
.compare(o
.keysHidden
); 
1387     if (v 
== 0) v 
= keyboard
.compare(o
.keyboard
); 
1388     if (v 
== 0) v 
= navHidden
.compare(o
.navHidden
); 
1389     if (v 
== 0) v 
= navigation
.compare(o
.navigation
); 
1390     if (v 
== 0) v 
= screenSize
.compare(o
.screenSize
); 
1391     if (v 
== 0) v 
= version
.compare(o
.version
); 
1395 const ResTable_config
& AaptGroupEntry::toParams() const 
1397     if (!mParamsChanged
) { 
1401     mParamsChanged 
= false; 
1402     ResTable_config
& params(mParams
); 
1403     memset(¶ms
, 0, sizeof(params
)); 
1404     getMccName(mcc
.string(), ¶ms
); 
1405     getMncName(mnc
.string(), ¶ms
); 
1406     getLocaleName(locale
.string(), ¶ms
); 
1407     getSmallestScreenWidthDpName(smallestScreenWidthDp
.string(), ¶ms
); 
1408     getScreenWidthDpName(screenWidthDp
.string(), ¶ms
); 
1409     getScreenHeightDpName(screenHeightDp
.string(), ¶ms
); 
1410     getScreenLayoutSizeName(screenLayoutSize
.string(), ¶ms
); 
1411     getScreenLayoutLongName(screenLayoutLong
.string(), ¶ms
); 
1412     getOrientationName(orientation
.string(), ¶ms
); 
1413     getUiModeTypeName(uiModeType
.string(), ¶ms
); 
1414     getUiModeNightName(uiModeNight
.string(), ¶ms
); 
1415     getDensityName(density
.string(), ¶ms
); 
1416     getTouchscreenName(touchscreen
.string(), ¶ms
); 
1417     getKeysHiddenName(keysHidden
.string(), ¶ms
); 
1418     getKeyboardName(keyboard
.string(), ¶ms
); 
1419     getNavHiddenName(navHidden
.string(), ¶ms
); 
1420     getNavigationName(navigation
.string(), ¶ms
); 
1421     getScreenSizeName(screenSize
.string(), ¶ms
); 
1422     getVersionName(version
.string(), ¶ms
); 
1424     // Fix up version number based on specified parameters. 
1426     if (params
.smallestScreenWidthDp 
!= ResTable_config::SCREENWIDTH_ANY
 
1427             || params
.screenWidthDp 
!= ResTable_config::SCREENWIDTH_ANY
 
1428             || params
.screenHeightDp 
!= ResTable_config::SCREENHEIGHT_ANY
) { 
1429         minSdk 
= SDK_HONEYCOMB_MR2
; 
1430     } else if ((params
.uiMode
&ResTable_config::MASK_UI_MODE_TYPE
) 
1431                 != ResTable_config::UI_MODE_TYPE_ANY
 
1432             ||  (params
.uiMode
&ResTable_config::MASK_UI_MODE_NIGHT
) 
1433                 != ResTable_config::UI_MODE_NIGHT_ANY
) { 
1435     } else if ((params
.screenLayout
&ResTable_config::MASK_SCREENSIZE
) 
1436                 != ResTable_config::SCREENSIZE_ANY
 
1437             ||  (params
.screenLayout
&ResTable_config::MASK_SCREENLONG
) 
1438                 != ResTable_config::SCREENLONG_ANY
 
1439             || params
.density 
!= ResTable_config::DENSITY_DEFAULT
) { 
1443     if (minSdk 
> params
.sdkVersion
) { 
1444         params
.sdkVersion 
= minSdk
; 
1450 // ========================================================================= 
1451 // ========================================================================= 
1452 // ========================================================================= 
1454 void* AaptFile::editData(size_t size
) 
1456     if (size 
<= mBufferSize
) { 
1460     size_t allocSize 
= (size
*3)/2; 
1461     void* buf 
= realloc(mData
, allocSize
); 
1467     mBufferSize 
= allocSize
; 
1471 void* AaptFile::editData(size_t* outSize
) 
1474         *outSize 
= mDataSize
; 
1479 void* AaptFile::padData(size_t wordSize
) 
1481     const size_t extra 
= mDataSize%wordSize
; 
1486     size_t initial 
= mDataSize
; 
1487     void* data 
= editData(initial
+(wordSize
-extra
)); 
1489         memset(((uint8_t*)data
) + initial
, 0, wordSize
-extra
); 
1494 status_t 
AaptFile::writeData(const void* data
, size_t size
) 
1496     size_t end 
= mDataSize
; 
1497     size_t total 
= size 
+ end
; 
1498     void* buf 
= editData(total
); 
1500         return UNKNOWN_ERROR
; 
1502     memcpy(((char*)buf
)+end
, data
, size
); 
1506 void AaptFile::clearData() 
1508     if (mData 
!= NULL
) free(mData
); 
1514 String8 
AaptFile::getPrintableSource() const 
1517         String8 
name(mGroupEntry
.toDirName(String8())); 
1518         name
.appendPath(mPath
); 
1519         name
.append(" #generated"); 
1525 // ========================================================================= 
1526 // ========================================================================= 
1527 // ========================================================================= 
1529 status_t 
AaptGroup::addFile(const sp
<AaptFile
>& file
) 
1531     if (mFiles
.indexOfKey(file
->getGroupEntry()) < 0) { 
1532         file
->mPath 
= mPath
; 
1533         mFiles
.add(file
->getGroupEntry(), file
); 
1538     printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n", 
1539             file
->getSourceFile().string(), 
1540             file
->getGroupEntry().toDirName(String8()).string(), 
1541             mLeaf
.string(), mPath
.string()); 
1544     SourcePos(file
->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.", 
1545                                                getPrintableSource().string()); 
1546     return UNKNOWN_ERROR
; 
1549 void AaptGroup::removeFile(size_t index
) 
1551         mFiles
.removeItemsAt(index
); 
1554 void AaptGroup::print(const String8
& prefix
) const 
1556     printf("%s%s\n", prefix
.string(), getPath().string()); 
1557     const size_t N
=mFiles
.size(); 
1559     for (i
=0; i
<N
; i
++) { 
1560         sp
<AaptFile
> file 
= mFiles
.valueAt(i
); 
1561         const AaptGroupEntry
& e 
= file
->getGroupEntry(); 
1562         if (file
->hasData()) { 
1563             printf("%s  Gen: (%s) %d bytes\n", prefix
.string(), e
.toDirName(String8()).string(), 
1564                     (int)file
->getSize()); 
1566             printf("%s  Src: (%s) %s\n", prefix
.string(), e
.toDirName(String8()).string(), 
1567                     file
->getPrintableSource().string()); 
1569         //printf("%s  File Group Entry: %s\n", prefix.string(), 
1570         //        file->getGroupEntry().toDirName(String8()).string()); 
1574 String8 
AaptGroup::getPrintableSource() const 
1576     if (mFiles
.size() > 0) { 
1577         // Arbitrarily pull the first source file out of the list. 
1578         return mFiles
.valueAt(0)->getPrintableSource(); 
1581     // Should never hit this case, but to be safe... 
1586 // ========================================================================= 
1587 // ========================================================================= 
1588 // ========================================================================= 
1590 status_t 
AaptDir::addFile(const String8
& name
, const sp
<AaptGroup
>& file
) 
1592     if (mFiles
.indexOfKey(name
) >= 0) { 
1593         return ALREADY_EXISTS
; 
1595     mFiles
.add(name
, file
); 
1599 status_t 
AaptDir::addDir(const String8
& name
, const sp
<AaptDir
>& dir
) 
1601     if (mDirs
.indexOfKey(name
) >= 0) { 
1602         return ALREADY_EXISTS
; 
1604     mDirs
.add(name
, dir
); 
1608 sp
<AaptDir
> AaptDir::makeDir(const String8
& path
) 
1611     String8 remain 
= path
; 
1613     sp
<AaptDir
> subdir 
= this; 
1614     while (name 
= remain
.walkPath(&remain
), remain 
!= "") { 
1615         subdir 
= subdir
->makeDir(name
); 
1618     ssize_t i 
= subdir
->mDirs
.indexOfKey(name
); 
1620         return subdir
->mDirs
.valueAt(i
); 
1622     sp
<AaptDir
> dir 
= new AaptDir(name
, subdir
->mPath
.appendPathCopy(name
)); 
1623     subdir
->mDirs
.add(name
, dir
); 
1627 void AaptDir::removeFile(const String8
& name
) 
1629     mFiles
.removeItem(name
); 
1632 void AaptDir::removeDir(const String8
& name
) 
1634     mDirs
.removeItem(name
); 
1637 status_t 
AaptDir::addLeafFile(const String8
& leafName
, const sp
<AaptFile
>& file
) 
1639     sp
<AaptGroup
> group
; 
1640     if (mFiles
.indexOfKey(leafName
) >= 0) { 
1641         group 
= mFiles
.valueFor(leafName
); 
1643         group 
= new AaptGroup(leafName
, mPath
.appendPathCopy(leafName
)); 
1644         mFiles
.add(leafName
, group
); 
1647     return group
->addFile(file
); 
1650 ssize_t 
AaptDir::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
, 
1651                             const AaptGroupEntry
& kind
, const String8
& resType
, 
1652                             sp
<FilePathStore
>& fullResPaths
) 
1654     Vector
<String8
> fileNames
; 
1658         dir 
= opendir(srcDir
.string()); 
1660             fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
)); 
1661             return UNKNOWN_ERROR
; 
1665          * Slurp the filenames out of the directory. 
1668             struct dirent
* entry
; 
1670             entry 
= readdir(dir
); 
1674             if (isHidden(srcDir
.string(), entry
->d_name
)) 
1677             String8 
name(entry
->d_name
); 
1678             fileNames
.add(name
); 
1679             // Add fully qualified path for dependency purposes 
1680             // if we're collecting them 
1681             if (fullResPaths 
!= NULL
) { 
1682                 fullResPaths
->add(srcDir
.appendPathCopy(name
)); 
1691      * Stash away the files and recursively descend into subdirectories. 
1693     const size_t N 
= fileNames
.size(); 
1695     for (i 
= 0; i 
< N
; i
++) { 
1696         String8 
pathName(srcDir
); 
1699         pathName
.appendPath(fileNames
[i
].string()); 
1700         type 
= getFileType(pathName
.string()); 
1701         if (type 
== kFileTypeDirectory
) { 
1703             bool notAdded 
= false; 
1704             if (mDirs
.indexOfKey(fileNames
[i
]) >= 0) { 
1705                 subdir 
= mDirs
.valueFor(fileNames
[i
]); 
1707                 subdir 
= new AaptDir(fileNames
[i
], mPath
.appendPathCopy(fileNames
[i
])); 
1710             ssize_t res 
= subdir
->slurpFullTree(bundle
, pathName
, kind
, 
1711                                                 resType
, fullResPaths
); 
1712             if (res 
< NO_ERROR
) { 
1715             if (res 
> 0 && notAdded
) { 
1716                 mDirs
.add(fileNames
[i
], subdir
); 
1719         } else if (type 
== kFileTypeRegular
) { 
1720             sp
<AaptFile
> file 
= new AaptFile(pathName
, kind
, resType
); 
1721             status_t err 
= addLeafFile(fileNames
[i
], file
); 
1722             if (err 
!= NO_ERROR
) { 
1729             if (bundle
->getVerbose()) 
1730                 printf("   (ignoring non-file/dir '%s')\n", pathName
.string()); 
1737 status_t 
AaptDir::validate() const 
1739     const size_t NF 
= mFiles
.size(); 
1740     const size_t ND 
= mDirs
.size(); 
1742     for (i 
= 0; i 
< NF
; i
++) { 
1743         if (!validateFileName(mFiles
.valueAt(i
)->getLeaf().string())) { 
1744             SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error( 
1745                     "Invalid filename.  Unable to add."); 
1746             return UNKNOWN_ERROR
; 
1750         for (j 
= i
+1; j 
< NF
; j
++) { 
1751             if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(), 
1752                            mFiles
.valueAt(j
)->getLeaf().string()) == 0) { 
1753                 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error( 
1754                         "File is case-insensitive equivalent to: %s", 
1755                         mFiles
.valueAt(j
)->getPrintableSource().string()); 
1756                 return UNKNOWN_ERROR
; 
1759             // TODO: if ".gz", check for non-.gz; if non-, check for ".gz" 
1760             // (this is mostly caught by the "marked" stuff, below) 
1763         for (j 
= 0; j 
< ND
; j
++) { 
1764             if (strcasecmp(mFiles
.valueAt(i
)->getLeaf().string(), 
1765                            mDirs
.valueAt(j
)->getLeaf().string()) == 0) { 
1766                 SourcePos(mFiles
.valueAt(i
)->getPrintableSource(), -1).error( 
1767                         "File conflicts with dir from: %s", 
1768                         mDirs
.valueAt(j
)->getPrintableSource().string()); 
1769                 return UNKNOWN_ERROR
; 
1774     for (i 
= 0; i 
< ND
; i
++) { 
1775         if (!validateFileName(mDirs
.valueAt(i
)->getLeaf().string())) { 
1776             SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error( 
1777                     "Invalid directory name, unable to add."); 
1778             return UNKNOWN_ERROR
; 
1782         for (j 
= i
+1; j 
< ND
; j
++) { 
1783             if (strcasecmp(mDirs
.valueAt(i
)->getLeaf().string(), 
1784                            mDirs
.valueAt(j
)->getLeaf().string()) == 0) { 
1785                 SourcePos(mDirs
.valueAt(i
)->getPrintableSource(), -1).error( 
1786                         "Directory is case-insensitive equivalent to: %s", 
1787                         mDirs
.valueAt(j
)->getPrintableSource().string()); 
1788                 return UNKNOWN_ERROR
; 
1792         status_t err 
= mDirs
.valueAt(i
)->validate(); 
1793         if (err 
!= NO_ERROR
) { 
1801 void AaptDir::print(const String8
& prefix
) const 
1803     const size_t ND
=getDirs().size(); 
1805     for (i
=0; i
<ND
; i
++) { 
1806         getDirs().valueAt(i
)->print(prefix
); 
1809     const size_t NF
=getFiles().size(); 
1810     for (i
=0; i
<NF
; i
++) { 
1811         getFiles().valueAt(i
)->print(prefix
); 
1815 String8 
AaptDir::getPrintableSource() const 
1817     if (mFiles
.size() > 0) { 
1818         // Arbitrarily pull the first file out of the list as the source dir. 
1819         return mFiles
.valueAt(0)->getPrintableSource().getPathDir(); 
1821     if (mDirs
.size() > 0) { 
1822         // Or arbitrarily pull the first dir out of the list as the source dir. 
1823         return mDirs
.valueAt(0)->getPrintableSource().getPathDir(); 
1826     // Should never hit this case, but to be safe... 
1831 // ========================================================================= 
1832 // ========================================================================= 
1833 // ========================================================================= 
1835 AaptAssets::AaptAssets() 
1836     : AaptDir(String8(), String8()), 
1837       mChanged(false), mHaveIncludedAssets(false), mRes(NULL
) 
1841 const SortedVector
<AaptGroupEntry
>& AaptAssets::getGroupEntries() const { 
1844     return mGroupEntries
; 
1847 status_t 
AaptAssets::addFile(const String8
& name
, const sp
<AaptGroup
>& file
) 
1850     return AaptDir::addFile(name
, file
); 
1853 sp
<AaptFile
> AaptAssets::addFile( 
1854         const String8
& filePath
, const AaptGroupEntry
& entry
, 
1855         const String8
& srcDir
, sp
<AaptGroup
>* outGroup
, 
1856         const String8
& resType
) 
1858     sp
<AaptDir
> dir 
= this; 
1859     sp
<AaptGroup
> group
; 
1861     String8 root
, remain(filePath
), partialPath
; 
1862     while (remain
.length() > 0) { 
1863         root 
= remain
.walkPath(&remain
); 
1864         partialPath
.appendPath(root
); 
1866         const String8 
rootStr(root
); 
1868         if (remain
.length() == 0) { 
1869             ssize_t i 
= dir
->getFiles().indexOfKey(rootStr
); 
1871                 group 
= dir
->getFiles().valueAt(i
); 
1873                 group 
= new AaptGroup(rootStr
, filePath
); 
1874                 status_t res 
= dir
->addFile(rootStr
, group
); 
1875                 if (res 
!= NO_ERROR
) { 
1879             file 
= new AaptFile(srcDir
.appendPathCopy(filePath
), entry
, resType
); 
1880             status_t res 
= group
->addFile(file
); 
1881             if (res 
!= NO_ERROR
) { 
1887             ssize_t i 
= dir
->getDirs().indexOfKey(rootStr
); 
1889                 dir 
= dir
->getDirs().valueAt(i
); 
1891                 sp
<AaptDir
> subdir 
= new AaptDir(rootStr
, partialPath
); 
1892                 status_t res 
= dir
->addDir(rootStr
, subdir
); 
1893                 if (res 
!= NO_ERROR
) { 
1901     mGroupEntries
.add(entry
); 
1902     if (outGroup
) *outGroup 
= group
; 
1906 void AaptAssets::addResource(const String8
& leafName
, const String8
& path
, 
1907                 const sp
<AaptFile
>& file
, const String8
& resType
) 
1909     sp
<AaptDir
> res 
= AaptDir::makeDir(kResString
); 
1910     String8 dirname 
= file
->getGroupEntry().toDirName(resType
); 
1911     sp
<AaptDir
> subdir 
= res
->makeDir(dirname
); 
1912     sp
<AaptGroup
> grr 
= new AaptGroup(leafName
, path
); 
1915     subdir
->addFile(leafName
, grr
); 
1919 ssize_t 
AaptAssets::slurpFromArgs(Bundle
* bundle
) 
1924     const Vector
<const char *>& resDirs 
= bundle
->getResourceSourceDirs(); 
1925     const size_t dirCount 
=resDirs
.size(); 
1926     sp
<AaptAssets
> current 
= this; 
1928     const int N 
= bundle
->getFileSpecCount(); 
1931      * If a package manifest was specified, include that first. 
1933     if (bundle
->getAndroidManifestFile() != NULL
) { 
1934         // place at root of zip. 
1935         String8 
srcFile(bundle
->getAndroidManifestFile()); 
1936         addFile(srcFile
.getPathLeaf(), AaptGroupEntry(), srcFile
.getPathDir(), 
1942      * If a directory of custom assets was supplied, slurp 'em up. 
1944     if (bundle
->getAssetSourceDir()) { 
1945         const char* assetDir 
= bundle
->getAssetSourceDir(); 
1947         FileType type 
= getFileType(assetDir
); 
1948         if (type 
== kFileTypeNonexistent
) { 
1949             fprintf(stderr
, "ERROR: asset directory '%s' does not exist\n", assetDir
); 
1950             return UNKNOWN_ERROR
; 
1952         if (type 
!= kFileTypeDirectory
) { 
1953             fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
); 
1954             return UNKNOWN_ERROR
; 
1957         String8 
assetRoot(assetDir
); 
1958         sp
<AaptDir
> assetAaptDir 
= makeDir(String8(kAssetDir
)); 
1959         AaptGroupEntry group
; 
1960         count 
= assetAaptDir
->slurpFullTree(bundle
, assetRoot
, group
, 
1961                                             String8(), mFullAssetPaths
); 
1967             mGroupEntries
.add(group
); 
1969         totalCount 
+= count
; 
1971         if (bundle
->getVerbose()) 
1972             printf("Found %d custom asset file%s in %s\n", 
1973                    count
, (count
==1) ? "" : "s", assetDir
); 
1977      * If a directory of resource-specific assets was supplied, slurp 'em up. 
1979     for (size_t i
=0; i
<dirCount
; i
++) { 
1980         const char *res 
= resDirs
[i
]; 
1982             type 
= getFileType(res
); 
1983             if (type 
== kFileTypeNonexistent
) { 
1984                 fprintf(stderr
, "ERROR: resource directory '%s' does not exist\n", res
); 
1985                 return UNKNOWN_ERROR
; 
1987             if (type 
== kFileTypeDirectory
) { 
1989                     sp
<AaptAssets
> nextOverlay 
= new AaptAssets(); 
1990                     current
->setOverlay(nextOverlay
); 
1991                     current 
= nextOverlay
; 
1992                     current
->setFullResPaths(mFullResPaths
); 
1994                 count 
= current
->slurpResourceTree(bundle
, String8(res
)); 
2000                 totalCount 
+= count
; 
2003                 fprintf(stderr
, "ERROR: '%s' is not a directory\n", res
); 
2004                 return UNKNOWN_ERROR
; 
2010      * Now do any additional raw files. 
2012     for (int arg
=0; arg
<N
; arg
++) { 
2013         const char* assetDir 
= bundle
->getFileSpecEntry(arg
); 
2015         FileType type 
= getFileType(assetDir
); 
2016         if (type 
== kFileTypeNonexistent
) { 
2017             fprintf(stderr
, "ERROR: input directory '%s' does not exist\n", assetDir
); 
2018             return UNKNOWN_ERROR
; 
2020         if (type 
!= kFileTypeDirectory
) { 
2021             fprintf(stderr
, "ERROR: '%s' is not a directory\n", assetDir
); 
2022             return UNKNOWN_ERROR
; 
2025         String8 
assetRoot(assetDir
); 
2027         if (bundle
->getVerbose()) 
2028             printf("Processing raw dir '%s'\n", (const char*) assetDir
); 
2031          * Do a recursive traversal of subdir tree.  We don't make any 
2032          * guarantees about ordering, so we're okay with an inorder search 
2033          * using whatever order the OS happens to hand back to us. 
2035         count 
= slurpFullTree(bundle
, assetRoot
, AaptGroupEntry(), String8(), mFullAssetPaths
); 
2037             /* failure; report error and remove archive */ 
2041         totalCount 
+= count
; 
2043         if (bundle
->getVerbose()) 
2044             printf("Found %d asset file%s in %s\n", 
2045                    count
, (count
==1) ? "" : "s", assetDir
); 
2049     if (count 
!= NO_ERROR
) { 
2054     count 
= filter(bundle
); 
2055     if (count 
!= NO_ERROR
) { 
2064 ssize_t 
AaptAssets::slurpFullTree(Bundle
* bundle
, const String8
& srcDir
, 
2065                                     const AaptGroupEntry
& kind
, 
2066                                     const String8
& resType
, 
2067                                     sp
<FilePathStore
>& fullResPaths
) 
2069     ssize_t res 
= AaptDir::slurpFullTree(bundle
, srcDir
, kind
, resType
, fullResPaths
); 
2071         mGroupEntries
.add(kind
); 
2077 ssize_t 
AaptAssets::slurpResourceTree(Bundle
* bundle
, const String8
& srcDir
) 
2081     DIR* dir 
= opendir(srcDir
.string()); 
2083         fprintf(stderr
, "ERROR: opendir(%s): %s\n", srcDir
.string(), strerror(errno
)); 
2084         return UNKNOWN_ERROR
; 
2090      * Run through the directory, looking for dirs that match the 
2094         struct dirent
* entry 
= readdir(dir
); 
2095         if (entry 
== NULL
) { 
2099         if (isHidden(srcDir
.string(), entry
->d_name
)) { 
2103         String8 
subdirName(srcDir
); 
2104         subdirName
.appendPath(entry
->d_name
); 
2106         AaptGroupEntry group
; 
2108         bool b 
= group
.initFromDirName(entry
->d_name
, &resType
); 
2110             fprintf(stderr
, "invalid resource directory name: %s/%s\n", srcDir
.string(), 
2116         if (bundle
->getMaxResVersion() != NULL 
&& group
.getVersionString().length() != 0) { 
2117             int maxResInt 
= atoi(bundle
->getMaxResVersion()); 
2118             const char *verString 
= group
.getVersionString().string(); 
2119             int dirVersionInt 
= atoi(verString 
+ 1); // skip 'v' in version name 
2120             if (dirVersionInt 
> maxResInt
) { 
2121               fprintf(stderr
, "max res %d, skipping %s\n", maxResInt
, entry
->d_name
); 
2126         FileType type 
= getFileType(subdirName
.string()); 
2128         if (type 
== kFileTypeDirectory
) { 
2129             sp
<AaptDir
> dir 
= makeDir(resType
); 
2130             ssize_t res 
= dir
->slurpFullTree(bundle
, subdirName
, group
, 
2131                                                 resType
, mFullResPaths
); 
2137                 mGroupEntries
.add(group
); 
2141             // Only add this directory if we don't already have a resource dir 
2142             // for the current type.  This ensures that we only add the dir once 
2144             sp
<AaptDir
> rdir 
= resDir(resType
); 
2149             if (bundle
->getVerbose()) { 
2150                 fprintf(stderr
, "   (ignoring file '%s')\n", subdirName
.string()); 
2166 AaptAssets::slurpResourceZip(Bundle
* bundle
, const char* filename
) 
2169     SortedVector
<AaptGroupEntry
> entries
; 
2171     ZipFile
* zip 
= new ZipFile
; 
2172     status_t err 
= zip
->open(filename
, ZipFile::kOpenReadOnly
); 
2173     if (err 
!= NO_ERROR
) { 
2174         fprintf(stderr
, "error opening zip file %s\n", filename
); 
2180     const int N 
= zip
->getNumEntries(); 
2181     for (int i
=0; i
<N
; i
++) { 
2182         ZipEntry
* entry 
= zip
->getEntryByIndex(i
); 
2183         if (entry
->getDeleted()) { 
2187         String8 
entryName(entry
->getFileName()); 
2189         String8 dirName 
= entryName
.getPathDir(); 
2190         sp
<AaptDir
> dir 
= dirName 
== "" ? this : makeDir(dirName
); 
2193         AaptGroupEntry kind
; 
2196         if (entryName
.walkPath(&remain
) == kResourceDir
) { 
2197             // these are the resources, pull their type out of the directory name 
2198             kind
.initFromDirName(remain
.walkPath().string(), &resType
); 
2200             // these are untyped and don't have an AaptGroupEntry 
2202         if (entries
.indexOf(kind
) < 0) { 
2204             mGroupEntries
.add(kind
); 
2207         // use the one from the zip file if they both exist. 
2208         dir
->removeFile(entryName
.getPathLeaf()); 
2210         sp
<AaptFile
> file 
= new AaptFile(entryName
, kind
, resType
); 
2211         status_t err 
= dir
->addLeafFile(entryName
.getPathLeaf(), file
); 
2212         if (err 
!= NO_ERROR
) { 
2213             fprintf(stderr
, "err=%s entryName=%s\n", strerror(err
), entryName
.string()); 
2217         file
->setCompressionMethod(entry
->getCompressionMethod()); 
2220         if (entryName 
== "AndroidManifest.xml") { 
2221             printf("AndroidManifest.xml\n"); 
2223         printf("\n\nfile: %s\n", entryName
.string()); 
2226         size_t len 
= entry
->getUncompressedLen(); 
2227         void* data 
= zip
->uncompress(entry
); 
2228         void* buf 
= file
->editData(len
); 
2229         memcpy(buf
, data
, len
); 
2233         const unsigned char* p 
= (unsigned char*)data
; 
2234         const unsigned char* end 
= p
+len
; 
2236         for (int i
=0; i
<32 && p 
< end
; i
++) { 
2237             printf("0x%03x ", i
*0x10 + OFF
); 
2238             for (int j
=0; j
<0x10 && p 
< end
; j
++) { 
2239                 printf(" %02x", *p
); 
2256 status_t 
AaptAssets::filter(Bundle
* bundle
) 
2258     ResourceFilter reqFilter
; 
2259     status_t err 
= reqFilter
.parse(bundle
->getConfigurations()); 
2260     if (err 
!= NO_ERROR
) { 
2264     ResourceFilter prefFilter
; 
2265     err 
= prefFilter
.parse(bundle
->getPreferredConfigurations()); 
2266     if (err 
!= NO_ERROR
) { 
2270     if (reqFilter
.isEmpty() && prefFilter
.isEmpty()) { 
2274     if (bundle
->getVerbose()) { 
2275         if (!reqFilter
.isEmpty()) { 
2276             printf("Applying required filter: %s\n", 
2277                     bundle
->getConfigurations()); 
2279         if (!prefFilter
.isEmpty()) { 
2280             printf("Applying preferred filter: %s\n", 
2281                     bundle
->getPreferredConfigurations()); 
2285     const Vector
<sp
<AaptDir
> >& resdirs 
= mResDirs
; 
2286     const size_t ND 
= resdirs
.size(); 
2287     for (size_t i
=0; i
<ND
; i
++) { 
2288         const sp
<AaptDir
>& dir 
= resdirs
.itemAt(i
); 
2289         if (dir
->getLeaf() == kValuesDir
) { 
2290             // The "value" dir is special since a single file defines 
2291             // multiple resources, so we can not do filtering on the 
2292             // files themselves. 
2295         if (dir
->getLeaf() == kMipmapDir
) { 
2296             // We also skip the "mipmap" directory, since the point of this 
2297             // is to include all densities without stripping.  If you put 
2298             // other configurations in here as well they won't be stripped 
2299             // either...  So don't do that.  Seriously.  What is wrong with you? 
2303         const size_t NG 
= dir
->getFiles().size(); 
2304         for (size_t j
=0; j
<NG
; j
++) { 
2305             sp
<AaptGroup
> grp 
= dir
->getFiles().valueAt(j
); 
2307             // First remove any configurations we know we don't need. 
2308             for (size_t k
=0; k
<grp
->getFiles().size(); k
++) { 
2309                 sp
<AaptFile
> file 
= grp
->getFiles().valueAt(k
); 
2310                 if (k 
== 0 && grp
->getFiles().size() == 1) { 
2311                     // If this is the only file left, we need to keep it. 
2312                     // Otherwise the resource IDs we are using will be inconsistent 
2313                     // with what we get when not stripping.  Sucky, but at least 
2314                     // for now we can rely on the back-end doing another filtering 
2315                     // pass to take this out and leave us with this resource name 
2316                     // containing no entries. 
2319                 if (file
->getPath().getPathExtension() == ".xml") { 
2320                     // We can't remove .xml files at this point, because when 
2321                     // we parse them they may add identifier resources, so 
2322                     // removing them can cause our resource identifiers to 
2323                     // become inconsistent. 
2326                 const ResTable_config
& config(file
->getGroupEntry().toParams()); 
2327                 if (!reqFilter
.match(config
)) { 
2328                     if (bundle
->getVerbose()) { 
2329                         printf("Pruning unneeded resource: %s\n", 
2330                                 file
->getPrintableSource().string()); 
2337             // Quick check: no preferred filters, nothing more to do. 
2338             if (prefFilter
.isEmpty()) { 
2342             // Now deal with preferred configurations. 
2343             for (int axis
=AXIS_START
; axis
<=AXIS_END
; axis
++) { 
2344                 for (size_t k
=0; k
<grp
->getFiles().size(); k
++) { 
2345                     sp
<AaptFile
> file 
= grp
->getFiles().valueAt(k
); 
2346                     if (k 
== 0 && grp
->getFiles().size() == 1) { 
2347                         // If this is the only file left, we need to keep it. 
2348                         // Otherwise the resource IDs we are using will be inconsistent 
2349                         // with what we get when not stripping.  Sucky, but at least 
2350                         // for now we can rely on the back-end doing another filtering 
2351                         // pass to take this out and leave us with this resource name 
2352                         // containing no entries. 
2355                     if (file
->getPath().getPathExtension() == ".xml") { 
2356                         // We can't remove .xml files at this point, because when 
2357                         // we parse them they may add identifier resources, so 
2358                         // removing them can cause our resource identifiers to 
2359                         // become inconsistent. 
2362                     const ResTable_config
& config(file
->getGroupEntry().toParams()); 
2363                     if (!prefFilter
.match(axis
, config
)) { 
2364                         // This is a resource we would prefer not to have.  Check 
2365                         // to see if have a similar variation that we would like 
2366                         // to have and, if so, we can drop it. 
2367                         for (size_t m
=0; m
<grp
->getFiles().size(); m
++) { 
2368                             if (m 
== k
) continue; 
2369                             sp
<AaptFile
> mfile 
= grp
->getFiles().valueAt(m
); 
2370                             const ResTable_config
& mconfig(mfile
->getGroupEntry().toParams()); 
2371                             if (AaptGroupEntry::configSameExcept(config
, mconfig
, axis
)) { 
2372                                 if (prefFilter
.match(axis
, mconfig
)) { 
2373                                     if (bundle
->getVerbose()) { 
2374                                         printf("Pruning unneeded resource: %s\n", 
2375                                                 file
->getPrintableSource().string()); 
2392 sp
<AaptSymbols
> AaptAssets::getSymbolsFor(const String8
& name
) 
2394     sp
<AaptSymbols
> sym 
= mSymbols
.valueFor(name
); 
2396         sym 
= new AaptSymbols(); 
2397         mSymbols
.add(name
, sym
); 
2402 status_t 
AaptAssets::buildIncludedResources(Bundle
* bundle
) 
2404     if (!mHaveIncludedAssets
) { 
2405         // Add in all includes. 
2406         const Vector
<const char*>& incl 
= bundle
->getPackageIncludes(); 
2407         const size_t N
=incl
.size(); 
2408         for (size_t i
=0; i
<N
; i
++) { 
2409             if (bundle
->getVerbose()) 
2410                 printf("Including resources from package: %s\n", incl
[i
]); 
2411             if (!mIncludedAssets
.addAssetPath(String8(incl
[i
]), NULL
)) { 
2412                 fprintf(stderr
, "ERROR: Asset package include '%s' not found.\n", 
2414                 return UNKNOWN_ERROR
; 
2417         mHaveIncludedAssets 
= true; 
2423 status_t 
AaptAssets::addIncludedResources(const sp
<AaptFile
>& file
) 
2425     const ResTable
& res 
= getIncludedResources(); 
2427     return const_cast<ResTable
&>(res
).add(file
->getData(), file
->getSize(), NULL
); 
2430 const ResTable
& AaptAssets::getIncludedResources() const 
2432     return mIncludedAssets
.getResources(false); 
2435 void AaptAssets::print(const String8
& prefix
) const 
2437     String8 
innerPrefix(prefix
); 
2438     innerPrefix
.append("  "); 
2439     String8 
innerInnerPrefix(innerPrefix
); 
2440     innerInnerPrefix
.append("  "); 
2441     printf("%sConfigurations:\n", prefix
.string()); 
2442     const size_t N
=mGroupEntries
.size(); 
2443     for (size_t i
=0; i
<N
; i
++) { 
2444         String8 cname 
= mGroupEntries
.itemAt(i
).toDirName(String8()); 
2445         printf("%s %s\n", prefix
.string(), 
2446                 cname 
!= "" ? cname
.string() : "(default)"); 
2449     printf("\n%sFiles:\n", prefix
.string()); 
2450     AaptDir::print(innerPrefix
); 
2452     printf("\n%sResource Dirs:\n", prefix
.string()); 
2453     const Vector
<sp
<AaptDir
> >& resdirs 
= mResDirs
; 
2454     const size_t NR 
= resdirs
.size(); 
2455     for (size_t i
=0; i
<NR
; i
++) { 
2456         const sp
<AaptDir
>& d 
= resdirs
.itemAt(i
); 
2457         printf("%s  Type %s\n", prefix
.string(), d
->getLeaf().string()); 
2458         d
->print(innerInnerPrefix
); 
2462 sp
<AaptDir
> AaptAssets::resDir(const String8
& name
) const 
2464     const Vector
<sp
<AaptDir
> >& resdirs 
= mResDirs
; 
2465     const size_t N 
= resdirs
.size(); 
2466     for (size_t i
=0; i
<N
; i
++) { 
2467         const sp
<AaptDir
>& d 
= resdirs
.itemAt(i
); 
2468         if (d
->getLeaf() == name
) { 
2476 valid_symbol_name(const String8
& symbol
) 
2478     static char const * const KEYWORDS
[] = { 
2479         "abstract", "assert", "boolean", "break", 
2480         "byte", "case", "catch", "char", "class", "const", "continue", 
2481         "default", "do", "double", "else", "enum", "extends", "final", 
2482         "finally", "float", "for", "goto", "if", "implements", "import", 
2483         "instanceof", "int", "interface", "long", "native", "new", "package", 
2484         "private", "protected", "public", "return", "short", "static", 
2485         "strictfp", "super", "switch", "synchronized", "this", "throw", 
2486         "throws", "transient", "try", "void", "volatile", "while", 
2487         "true", "false", "null", 
2490     const char*const* k 
= KEYWORDS
; 
2491     const char*const s 
= symbol
.string(); 
2493         if (0 == strcmp(s
, *k
)) {