Home | History | Annotate | Download | only in aapt
      1 //
      2 // Copyright 2006 The Android Open Source Project
      3 //
      4 
      5 #include "AaptAssets.h"
      6 #include "ResourceFilter.h"
      7 #include "Main.h"
      8 
      9 #include <utils/misc.h>
     10 #include <utils/SortedVector.h>
     11 
     12 #include <ctype.h>
     13 #include <dirent.h>
     14 #include <errno.h>
     15 
     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;
     24 
     25 static const String8 kResString(kResourceDir);
     26 
     27 /*
     28  * Names of asset files must meet the following criteria:
     29  *
     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 { '/' '\\' ':' }
     34  *
     35  * Pass in just the filename, not the full path.
     36  */
     37 static bool validateFileName(const char* fileName)
     38 {
     39     const char* cp = fileName;
     40     size_t len = 0;
     41 
     42     while (*cp != '\0') {
     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
     49         cp++;
     50         len++;
     51     }
     52 
     53     if (len < 1 || len > kMaxAssetFileName)
     54         return false;               // reject empty or too long
     55 
     56     return true;
     57 }
     58 
     59 // The default to use if no other ignore pattern is defined.
     60 const char * const gDefaultIgnoreAssets =
     61     "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~";
     62 // The ignore pattern that can be passed via --ignore-assets in Main.cpp
     63 const char * gUserIgnoreAssets = NULL;
     64 
     65 static bool isHidden(const char *root, const char *path)
     66 {
     67     // Patterns syntax:
     68     // - Delimiter is :
     69     // - Entry can start with the flag ! to avoid printing a warning
     70     //   about the file being ignored.
     71     // - Entry can have the flag "<dir>" to match only directories
     72     //   or <file> to match only files. Default is to match both.
     73     // - Entry can be a simplified glob "<prefix>*" or "*<suffix>"
     74     //   where prefix/suffix must have at least 1 character (so that
     75     //   we don't match a '*' catch-all pattern.)
     76     // - The special filenames "." and ".." are always ignored.
     77     // - Otherwise the full string is matched.
     78     // - match is not case-sensitive.
     79 
     80     if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
     81         return true;
     82     }
     83 
     84     const char *delim = ":";
     85     const char *p = gUserIgnoreAssets;
     86     if (!p || !p[0]) {
     87         p = getenv("ANDROID_AAPT_IGNORE");
     88     }
     89     if (!p || !p[0]) {
     90         p = gDefaultIgnoreAssets;
     91     }
     92     char *patterns = strdup(p);
     93 
     94     bool ignore = false;
     95     bool chatty = true;
     96     char *matchedPattern = NULL;
     97 
     98     String8 fullPath(root);
     99     fullPath.appendPath(path);
    100     FileType type = getFileType(fullPath);
    101 
    102     int plen = strlen(path);
    103 
    104     // Note: we don't have strtok_r under mingw.
    105     for(char *token = strtok(patterns, delim);
    106             !ignore && token != NULL;
    107             token = strtok(NULL, delim)) {
    108         chatty = token[0] != '!';
    109         if (!chatty) token++; // skip !
    110         if (strncasecmp(token, "<dir>" , 5) == 0) {
    111             if (type != kFileTypeDirectory) continue;
    112             token += 5;
    113         }
    114         if (strncasecmp(token, "<file>", 6) == 0) {
    115             if (type != kFileTypeRegular) continue;
    116             token += 6;
    117         }
    118 
    119         matchedPattern = token;
    120         int n = strlen(token);
    121 
    122         if (token[0] == '*') {
    123             // Match *suffix
    124             token++;
    125             n--;
    126             if (n <= plen) {
    127                 ignore = strncasecmp(token, path + plen - n, n) == 0;
    128             }
    129         } else if (n > 1 && token[n - 1] == '*') {
    130             // Match prefix*
    131             ignore = strncasecmp(token, path, n - 1) == 0;
    132         } else {
    133             ignore = strcasecmp(token, path) == 0;
    134         }
    135     }
    136 
    137     if (ignore && chatty) {
    138         fprintf(stderr, "    (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
    139                 type == kFileTypeDirectory ? "dir" : "file",
    140                 path,
    141                 matchedPattern ? matchedPattern : "");
    142     }
    143 
    144     free(patterns);
    145     return ignore;
    146 }
    147 
    148 // =========================================================================
    149 // =========================================================================
    150 // =========================================================================
    151 
    152 status_t
    153 AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value)
    154 {
    155     ResTable_config config;
    156 
    157     // IMSI - MCC
    158     if (getMccName(part.string(), &config)) {
    159         *axis = AXIS_MCC;
    160         *value = config.mcc;
    161         return 0;
    162     }
    163 
    164     // IMSI - MNC
    165     if (getMncName(part.string(), &config)) {
    166         *axis = AXIS_MNC;
    167         *value = config.mnc;
    168         return 0;
    169     }
    170 
    171     // locale - language
    172     if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
    173         *axis = AXIS_LANGUAGE;
    174         *value = part[1] << 8 | part[0];
    175         return 0;
    176     }
    177 
    178     // locale - language_REGION
    179     if (part.length() == 5 && isalpha(part[0]) && isalpha(part[1])
    180             && part[2] == '_' && isalpha(part[3]) && isalpha(part[4])) {
    181         *axis = AXIS_LANGUAGE;
    182         *value = (part[4] << 24) | (part[3] << 16) | (part[1] << 8) | (part[0]);
    183         return 0;
    184     }
    185 
    186     // layout direction
    187     if (getLayoutDirectionName(part.string(), &config)) {
    188         *axis = AXIS_LAYOUTDIR;
    189         *value = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
    190         return 0;
    191     }
    192 
    193     // smallest screen dp width
    194     if (getSmallestScreenWidthDpName(part.string(), &config)) {
    195         *axis = AXIS_SMALLESTSCREENWIDTHDP;
    196         *value = config.smallestScreenWidthDp;
    197         return 0;
    198     }
    199 
    200     // screen dp width
    201     if (getScreenWidthDpName(part.string(), &config)) {
    202         *axis = AXIS_SCREENWIDTHDP;
    203         *value = config.screenWidthDp;
    204         return 0;
    205     }
    206 
    207     // screen dp height
    208     if (getScreenHeightDpName(part.string(), &config)) {
    209         *axis = AXIS_SCREENHEIGHTDP;
    210         *value = config.screenHeightDp;
    211         return 0;
    212     }
    213 
    214     // screen layout size
    215     if (getScreenLayoutSizeName(part.string(), &config)) {
    216         *axis = AXIS_SCREENLAYOUTSIZE;
    217         *value = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
    218         return 0;
    219     }
    220 
    221     // screen layout long
    222     if (getScreenLayoutLongName(part.string(), &config)) {
    223         *axis = AXIS_SCREENLAYOUTLONG;
    224         *value = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
    225         return 0;
    226     }
    227 
    228     // orientation
    229     if (getOrientationName(part.string(), &config)) {
    230         *axis = AXIS_ORIENTATION;
    231         *value = config.orientation;
    232         return 0;
    233     }
    234 
    235     // ui mode type
    236     if (getUiModeTypeName(part.string(), &config)) {
    237         *axis = AXIS_UIMODETYPE;
    238         *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
    239         return 0;
    240     }
    241 
    242     // ui mode night
    243     if (getUiModeNightName(part.string(), &config)) {
    244         *axis = AXIS_UIMODENIGHT;
    245         *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
    246         return 0;
    247     }
    248 
    249     // density
    250     if (getDensityName(part.string(), &config)) {
    251         *axis = AXIS_DENSITY;
    252         *value = config.density;
    253         return 0;
    254     }
    255 
    256     // touchscreen
    257     if (getTouchscreenName(part.string(), &config)) {
    258         *axis = AXIS_TOUCHSCREEN;
    259         *value = config.touchscreen;
    260         return 0;
    261     }
    262 
    263     // keyboard hidden
    264     if (getKeysHiddenName(part.string(), &config)) {
    265         *axis = AXIS_KEYSHIDDEN;
    266         *value = config.inputFlags;
    267         return 0;
    268     }
    269 
    270     // keyboard
    271     if (getKeyboardName(part.string(), &config)) {
    272         *axis = AXIS_KEYBOARD;
    273         *value = config.keyboard;
    274         return 0;
    275     }
    276 
    277     // navigation hidden
    278     if (getNavHiddenName(part.string(), &config)) {
    279         *axis = AXIS_NAVHIDDEN;
    280         *value = config.inputFlags;
    281         return 0;
    282     }
    283 
    284     // navigation
    285     if (getNavigationName(part.string(), &config)) {
    286         *axis = AXIS_NAVIGATION;
    287         *value = config.navigation;
    288         return 0;
    289     }
    290 
    291     // screen size
    292     if (getScreenSizeName(part.string(), &config)) {
    293         *axis = AXIS_SCREENSIZE;
    294         *value = config.screenSize;
    295         return 0;
    296     }
    297 
    298     // version
    299     if (getVersionName(part.string(), &config)) {
    300         *axis = AXIS_VERSION;
    301         *value = config.version;
    302         return 0;
    303     }
    304 
    305     return 1;
    306 }
    307 
    308 uint32_t
    309 AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
    310 {
    311     switch (axis) {
    312         case AXIS_MCC:
    313             return config.mcc;
    314         case AXIS_MNC:
    315             return config.mnc;
    316         case AXIS_LANGUAGE:
    317             return (((uint32_t)config.country[1]) << 24) | (((uint32_t)config.country[0]) << 16)
    318                 | (((uint32_t)config.language[1]) << 8) | (config.language[0]);
    319         case AXIS_LAYOUTDIR:
    320             return config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
    321         case AXIS_SCREENLAYOUTSIZE:
    322             return config.screenLayout&ResTable_config::MASK_SCREENSIZE;
    323         case AXIS_ORIENTATION:
    324             return config.orientation;
    325         case AXIS_UIMODETYPE:
    326             return (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
    327         case AXIS_UIMODENIGHT:
    328             return (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
    329         case AXIS_DENSITY:
    330             return config.density;
    331         case AXIS_TOUCHSCREEN:
    332             return config.touchscreen;
    333         case AXIS_KEYSHIDDEN:
    334             return config.inputFlags;
    335         case AXIS_KEYBOARD:
    336             return config.keyboard;
    337         case AXIS_NAVIGATION:
    338             return config.navigation;
    339         case AXIS_SCREENSIZE:
    340             return config.screenSize;
    341         case AXIS_SMALLESTSCREENWIDTHDP:
    342             return config.smallestScreenWidthDp;
    343         case AXIS_SCREENWIDTHDP:
    344             return config.screenWidthDp;
    345         case AXIS_SCREENHEIGHTDP:
    346             return config.screenHeightDp;
    347         case AXIS_VERSION:
    348             return config.version;
    349     }
    350     return 0;
    351 }
    352 
    353 bool
    354 AaptGroupEntry::configSameExcept(const ResTable_config& config,
    355         const ResTable_config& otherConfig, int axis)
    356 {
    357     for (int i=AXIS_START; i<=AXIS_END; i++) {
    358         if (i == axis) {
    359             continue;
    360         }
    361         if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
    362             return false;
    363         }
    364     }
    365     return true;
    366 }
    367 
    368 bool
    369 AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
    370 {
    371     mParamsChanged = true;
    372 
    373     Vector<String8> parts;
    374 
    375     String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
    376     String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
    377     String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
    378 
    379     const char *p = dir;
    380     const char *q;
    381     while (NULL != (q = strchr(p, '-'))) {
    382         String8 val(p, q-p);
    383         val.toLower();
    384         parts.add(val);
    385         //printf("part: %s\n", parts[parts.size()-1].string());
    386         p = q+1;
    387     }
    388     String8 val(p);
    389     val.toLower();
    390     parts.add(val);
    391     //printf("part: %s\n", parts[parts.size()-1].string());
    392 
    393     const int N = parts.size();
    394     int index = 0;
    395     String8 part = parts[index];
    396 
    397     // resource type
    398     if (!isValidResourceType(part)) {
    399         return false;
    400     }
    401     *resType = part;
    402 
    403     index++;
    404     if (index == N) {
    405         goto success;
    406     }
    407     part = parts[index];
    408 
    409     // imsi - mcc
    410     if (getMccName(part.string())) {
    411         mcc = part;
    412 
    413         index++;
    414         if (index == N) {
    415             goto success;
    416         }
    417         part = parts[index];
    418     } else {
    419         //printf("not mcc: %s\n", part.string());
    420     }
    421 
    422     // imsi - mnc
    423     if (getMncName(part.string())) {
    424         mnc = part;
    425 
    426         index++;
    427         if (index == N) {
    428             goto success;
    429         }
    430         part = parts[index];
    431     } else {
    432         //printf("not mcc: %s\n", part.string());
    433     }
    434 
    435     // locale - language
    436     if (part.length() == 2 && isalpha(part[0]) && isalpha(part[1])) {
    437         loc = part;
    438 
    439         index++;
    440         if (index == N) {
    441             goto success;
    442         }
    443         part = parts[index];
    444     } else {
    445         //printf("not language: %s\n", part.string());
    446     }
    447 
    448     // locale - region
    449     if (loc.length() > 0
    450             && part.length() == 3 && part[0] == 'r' && part[0] && part[1]) {
    451         loc += "-";
    452         part.toUpper();
    453         loc += part.string() + 1;
    454 
    455         index++;
    456         if (index == N) {
    457             goto success;
    458         }
    459         part = parts[index];
    460     } else {
    461         //printf("not region: %s\n", part.string());
    462     }
    463 
    464     if (getLayoutDirectionName(part.string())) {
    465         layoutDir = part;
    466 
    467         index++;
    468         if (index == N) {
    469             goto success;
    470         }
    471         part = parts[index];
    472     } else {
    473         //printf("not layout direction: %s\n", part.string());
    474     }
    475 
    476     if (getSmallestScreenWidthDpName(part.string())) {
    477         smallestwidthdp = part;
    478 
    479         index++;
    480         if (index == N) {
    481             goto success;
    482         }
    483         part = parts[index];
    484     } else {
    485         //printf("not smallest screen width dp: %s\n", part.string());
    486     }
    487 
    488     if (getScreenWidthDpName(part.string())) {
    489         widthdp = part;
    490 
    491         index++;
    492         if (index == N) {
    493             goto success;
    494         }
    495         part = parts[index];
    496     } else {
    497         //printf("not screen width dp: %s\n", part.string());
    498     }
    499 
    500     if (getScreenHeightDpName(part.string())) {
    501         heightdp = part;
    502 
    503         index++;
    504         if (index == N) {
    505             goto success;
    506         }
    507         part = parts[index];
    508     } else {
    509         //printf("not screen height dp: %s\n", part.string());
    510     }
    511 
    512     if (getScreenLayoutSizeName(part.string())) {
    513         layoutsize = part;
    514 
    515         index++;
    516         if (index == N) {
    517             goto success;
    518         }
    519         part = parts[index];
    520     } else {
    521         //printf("not screen layout size: %s\n", part.string());
    522     }
    523 
    524     if (getScreenLayoutLongName(part.string())) {
    525         layoutlong = part;
    526 
    527         index++;
    528         if (index == N) {
    529             goto success;
    530         }
    531         part = parts[index];
    532     } else {
    533         //printf("not screen layout long: %s\n", part.string());
    534     }
    535 
    536     // orientation
    537     if (getOrientationName(part.string())) {
    538         orient = part;
    539 
    540         index++;
    541         if (index == N) {
    542             goto success;
    543         }
    544         part = parts[index];
    545     } else {
    546         //printf("not orientation: %s\n", part.string());
    547     }
    548 
    549     // ui mode type
    550     if (getUiModeTypeName(part.string())) {
    551         uiModeType = part;
    552 
    553         index++;
    554         if (index == N) {
    555             goto success;
    556         }
    557         part = parts[index];
    558     } else {
    559         //printf("not ui mode type: %s\n", part.string());
    560     }
    561 
    562     // ui mode night
    563     if (getUiModeNightName(part.string())) {
    564         uiModeNight = part;
    565 
    566         index++;
    567         if (index == N) {
    568             goto success;
    569         }
    570         part = parts[index];
    571     } else {
    572         //printf("not ui mode night: %s\n", part.string());
    573     }
    574 
    575     // density
    576     if (getDensityName(part.string())) {
    577         den = part;
    578 
    579         index++;
    580         if (index == N) {
    581             goto success;
    582         }
    583         part = parts[index];
    584     } else {
    585         //printf("not density: %s\n", part.string());
    586     }
    587 
    588     // touchscreen
    589     if (getTouchscreenName(part.string())) {
    590         touch = part;
    591 
    592         index++;
    593         if (index == N) {
    594             goto success;
    595         }
    596         part = parts[index];
    597     } else {
    598         //printf("not touchscreen: %s\n", part.string());
    599     }
    600 
    601     // keyboard hidden
    602     if (getKeysHiddenName(part.string())) {
    603         keysHidden = part;
    604 
    605         index++;
    606         if (index == N) {
    607             goto success;
    608         }
    609         part = parts[index];
    610     } else {
    611         //printf("not keysHidden: %s\n", part.string());
    612     }
    613 
    614     // keyboard
    615     if (getKeyboardName(part.string())) {
    616         key = part;
    617 
    618         index++;
    619         if (index == N) {
    620             goto success;
    621         }
    622         part = parts[index];
    623     } else {
    624         //printf("not keyboard: %s\n", part.string());
    625     }
    626 
    627     // navigation hidden
    628     if (getNavHiddenName(part.string())) {
    629         navHidden = part;
    630 
    631         index++;
    632         if (index == N) {
    633             goto success;
    634         }
    635         part = parts[index];
    636     } else {
    637         //printf("not navHidden: %s\n", part.string());
    638     }
    639 
    640     if (getNavigationName(part.string())) {
    641         nav = part;
    642 
    643         index++;
    644         if (index == N) {
    645             goto success;
    646         }
    647         part = parts[index];
    648     } else {
    649         //printf("not navigation: %s\n", part.string());
    650     }
    651 
    652     if (getScreenSizeName(part.string())) {
    653         size = part;
    654 
    655         index++;
    656         if (index == N) {
    657             goto success;
    658         }
    659         part = parts[index];
    660     } else {
    661         //printf("not screen size: %s\n", part.string());
    662     }
    663 
    664     if (getVersionName(part.string())) {
    665         vers = part;
    666 
    667         index++;
    668         if (index == N) {
    669             goto success;
    670         }
    671         part = parts[index];
    672     } else {
    673         //printf("not version: %s\n", part.string());
    674     }
    675 
    676     // if there are extra parts, it doesn't match
    677     return false;
    678 
    679 success:
    680     this->mcc = mcc;
    681     this->mnc = mnc;
    682     this->locale = loc;
    683     this->screenLayoutSize = layoutsize;
    684     this->screenLayoutLong = layoutlong;
    685     this->smallestScreenWidthDp = smallestwidthdp;
    686     this->screenWidthDp = widthdp;
    687     this->screenHeightDp = heightdp;
    688     this->orientation = orient;
    689     this->uiModeType = uiModeType;
    690     this->uiModeNight = uiModeNight;
    691     this->density = den;
    692     this->touchscreen = touch;
    693     this->keysHidden = keysHidden;
    694     this->keyboard = key;
    695     this->navHidden = navHidden;
    696     this->navigation = nav;
    697     this->screenSize = size;
    698     this->layoutDirection = layoutDir;
    699     this->version = vers;
    700 
    701     // what is this anyway?
    702     this->vendor = "";
    703 
    704     return true;
    705 }
    706 
    707 String8
    708 AaptGroupEntry::toString() const
    709 {
    710     String8 s = this->mcc;
    711     s += ",";
    712     s += this->mnc;
    713     s += ",";
    714     s += this->locale;
    715     s += ",";
    716     s += layoutDirection;
    717     s += ",";
    718     s += smallestScreenWidthDp;
    719     s += ",";
    720     s += screenWidthDp;
    721     s += ",";
    722     s += screenHeightDp;
    723     s += ",";
    724     s += screenLayoutSize;
    725     s += ",";
    726     s += screenLayoutLong;
    727     s += ",";
    728     s += this->orientation;
    729     s += ",";
    730     s += uiModeType;
    731     s += ",";
    732     s += uiModeNight;
    733     s += ",";
    734     s += density;
    735     s += ",";
    736     s += touchscreen;
    737     s += ",";
    738     s += keysHidden;
    739     s += ",";
    740     s += keyboard;
    741     s += ",";
    742     s += navHidden;
    743     s += ",";
    744     s += navigation;
    745     s += ",";
    746     s += screenSize;
    747     s += ",";
    748     s += version;
    749     return s;
    750 }
    751 
    752 String8
    753 AaptGroupEntry::toDirName(const String8& resType) const
    754 {
    755     String8 s = resType;
    756     if (this->mcc != "") {
    757         if (s.length() > 0) {
    758             s += "-";
    759         }
    760         s += mcc;
    761     }
    762     if (this->mnc != "") {
    763         if (s.length() > 0) {
    764             s += "-";
    765         }
    766         s += mnc;
    767     }
    768     if (this->locale != "") {
    769         if (s.length() > 0) {
    770             s += "-";
    771         }
    772         s += locale;
    773     }
    774     if (this->layoutDirection != "") {
    775         if (s.length() > 0) {
    776             s += "-";
    777         }
    778         s += layoutDirection;
    779     }
    780     if (this->smallestScreenWidthDp != "") {
    781         if (s.length() > 0) {
    782             s += "-";
    783         }
    784         s += smallestScreenWidthDp;
    785     }
    786     if (this->screenWidthDp != "") {
    787         if (s.length() > 0) {
    788             s += "-";
    789         }
    790         s += screenWidthDp;
    791     }
    792     if (this->screenHeightDp != "") {
    793         if (s.length() > 0) {
    794             s += "-";
    795         }
    796         s += screenHeightDp;
    797     }
    798     if (this->screenLayoutSize != "") {
    799         if (s.length() > 0) {
    800             s += "-";
    801         }
    802         s += screenLayoutSize;
    803     }
    804     if (this->screenLayoutLong != "") {
    805         if (s.length() > 0) {
    806             s += "-";
    807         }
    808         s += screenLayoutLong;
    809     }
    810     if (this->orientation != "") {
    811         if (s.length() > 0) {
    812             s += "-";
    813         }
    814         s += orientation;
    815     }
    816     if (this->uiModeType != "") {
    817         if (s.length() > 0) {
    818             s += "-";
    819         }
    820         s += uiModeType;
    821     }
    822     if (this->uiModeNight != "") {
    823         if (s.length() > 0) {
    824             s += "-";
    825         }
    826         s += uiModeNight;
    827     }
    828     if (this->density != "") {
    829         if (s.length() > 0) {
    830             s += "-";
    831         }
    832         s += density;
    833     }
    834     if (this->touchscreen != "") {
    835         if (s.length() > 0) {
    836             s += "-";
    837         }
    838         s += touchscreen;
    839     }
    840     if (this->keysHidden != "") {
    841         if (s.length() > 0) {
    842             s += "-";
    843         }
    844         s += keysHidden;
    845     }
    846     if (this->keyboard != "") {
    847         if (s.length() > 0) {
    848             s += "-";
    849         }
    850         s += keyboard;
    851     }
    852     if (this->navHidden != "") {
    853         if (s.length() > 0) {
    854             s += "-";
    855         }
    856         s += navHidden;
    857     }
    858     if (this->navigation != "") {
    859         if (s.length() > 0) {
    860             s += "-";
    861         }
    862         s += navigation;
    863     }
    864     if (this->screenSize != "") {
    865         if (s.length() > 0) {
    866             s += "-";
    867         }
    868         s += screenSize;
    869     }
    870     if (this->version != "") {
    871         if (s.length() > 0) {
    872             s += "-";
    873         }
    874         s += version;
    875     }
    876 
    877     return s;
    878 }
    879 
    880 bool AaptGroupEntry::getMccName(const char* name,
    881                                     ResTable_config* out)
    882 {
    883     if (strcmp(name, kWildcardName) == 0) {
    884         if (out) out->mcc = 0;
    885         return true;
    886     }
    887     const char* c = name;
    888     if (tolower(*c) != 'm') return false;
    889     c++;
    890     if (tolower(*c) != 'c') return false;
    891     c++;
    892     if (tolower(*c) != 'c') return false;
    893     c++;
    894 
    895     const char* val = c;
    896 
    897     while (*c >= '0' && *c <= '9') {
    898         c++;
    899     }
    900     if (*c != 0) return false;
    901     if (c-val != 3) return false;
    902 
    903     int d = atoi(val);
    904     if (d != 0) {
    905         if (out) out->mcc = d;
    906         return true;
    907     }
    908 
    909     return false;
    910 }
    911 
    912 bool AaptGroupEntry::getMncName(const char* name,
    913                                     ResTable_config* out)
    914 {
    915     if (strcmp(name, kWildcardName) == 0) {
    916         if (out) out->mcc = 0;
    917         return true;
    918     }
    919     const char* c = name;
    920     if (tolower(*c) != 'm') return false;
    921     c++;
    922     if (tolower(*c) != 'n') return false;
    923     c++;
    924     if (tolower(*c) != 'c') return false;
    925     c++;
    926 
    927     const char* val = c;
    928 
    929     while (*c >= '0' && *c <= '9') {
    930         c++;
    931     }
    932     if (*c != 0) return false;
    933     if (c-val == 0 || c-val > 3) return false;
    934 
    935     if (out) {
    936         out->mnc = atoi(val);
    937     }
    938 
    939     return true;
    940 }
    941 
    942 /*
    943  * Does this directory name fit the pattern of a locale dir ("en-rUS" or
    944  * "default")?
    945  *
    946  * TODO: Should insist that the first two letters are lower case, and the
    947  * second two are upper.
    948  */
    949 bool AaptGroupEntry::getLocaleName(const char* fileName,
    950                                    ResTable_config* out)
    951 {
    952     if (strcmp(fileName, kWildcardName) == 0
    953             || strcmp(fileName, kDefaultLocale) == 0) {
    954         if (out) {
    955             out->language[0] = 0;
    956             out->language[1] = 0;
    957             out->country[0] = 0;
    958             out->country[1] = 0;
    959         }
    960         return true;
    961     }
    962 
    963     if (strlen(fileName) == 2 && isalpha(fileName[0]) && isalpha(fileName[1])) {
    964         if (out) {
    965             out->language[0] = fileName[0];
    966             out->language[1] = fileName[1];
    967             out->country[0] = 0;
    968             out->country[1] = 0;
    969         }
    970         return true;
    971     }
    972 
    973     if (strlen(fileName) == 5 &&
    974         isalpha(fileName[0]) &&
    975         isalpha(fileName[1]) &&
    976         fileName[2] == '-' &&
    977         isalpha(fileName[3]) &&
    978         isalpha(fileName[4])) {
    979         if (out) {
    980             out->language[0] = fileName[0];
    981             out->language[1] = fileName[1];
    982             out->country[0] = fileName[3];
    983             out->country[1] = fileName[4];
    984         }
    985         return true;
    986     }
    987 
    988     return false;
    989 }
    990 
    991 bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
    992 {
    993     if (strcmp(name, kWildcardName) == 0) {
    994         if (out) out->screenLayout =
    995                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
    996                 | ResTable_config::LAYOUTDIR_ANY;
    997         return true;
    998     } else if (strcmp(name, "ldltr") == 0) {
    999         if (out) out->screenLayout =
   1000                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
   1001                 | ResTable_config::LAYOUTDIR_LTR;
   1002         return true;
   1003     } else if (strcmp(name, "ldrtl") == 0) {
   1004         if (out) out->screenLayout =
   1005                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
   1006                 | ResTable_config::LAYOUTDIR_RTL;
   1007         return true;
   1008     }
   1009 
   1010     return false;
   1011 }
   1012 
   1013 bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
   1014                                      ResTable_config* out)
   1015 {
   1016     if (strcmp(name, kWildcardName) == 0) {
   1017         if (out) out->screenLayout =
   1018                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
   1019                 | ResTable_config::SCREENSIZE_ANY;
   1020         return true;
   1021     } else if (strcmp(name, "small") == 0) {
   1022         if (out) out->screenLayout =
   1023                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
   1024                 | ResTable_config::SCREENSIZE_SMALL;
   1025         return true;
   1026     } else if (strcmp(name, "normal") == 0) {
   1027         if (out) out->screenLayout =
   1028                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
   1029                 | ResTable_config::SCREENSIZE_NORMAL;
   1030         return true;
   1031     } else if (strcmp(name, "large") == 0) {
   1032         if (out) out->screenLayout =
   1033                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
   1034                 | ResTable_config::SCREENSIZE_LARGE;
   1035         return true;
   1036     } else if (strcmp(name, "xlarge") == 0) {
   1037         if (out) out->screenLayout =
   1038                 (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
   1039                 | ResTable_config::SCREENSIZE_XLARGE;
   1040         return true;
   1041     }
   1042 
   1043     return false;
   1044 }
   1045 
   1046 bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
   1047                                      ResTable_config* out)
   1048 {
   1049     if (strcmp(name, kWildcardName) == 0) {
   1050         if (out) out->screenLayout =
   1051                 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
   1052                 | ResTable_config::SCREENLONG_ANY;
   1053         return true;
   1054     } else if (strcmp(name, "long") == 0) {
   1055         if (out) out->screenLayout =
   1056                 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
   1057                 | ResTable_config::SCREENLONG_YES;
   1058         return true;
   1059     } else if (strcmp(name, "notlong") == 0) {
   1060         if (out) out->screenLayout =
   1061                 (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
   1062                 | ResTable_config::SCREENLONG_NO;
   1063         return true;
   1064     }
   1065 
   1066     return false;
   1067 }
   1068 
   1069 bool AaptGroupEntry::getOrientationName(const char* name,
   1070                                         ResTable_config* out)
   1071 {
   1072     if (strcmp(name, kWildcardName) == 0) {
   1073         if (out) out->orientation = out->ORIENTATION_ANY;
   1074         return true;
   1075     } else if (strcmp(name, "port") == 0) {
   1076         if (out) out->orientation = out->ORIENTATION_PORT;
   1077         return true;
   1078     } else if (strcmp(name, "land") == 0) {
   1079         if (out) out->orientation = out->ORIENTATION_LAND;
   1080         return true;
   1081     } else if (strcmp(name, "square") == 0) {
   1082         if (out) out->orientation = out->ORIENTATION_SQUARE;
   1083         return true;
   1084     }
   1085 
   1086     return false;
   1087 }
   1088 
   1089 bool AaptGroupEntry::getUiModeTypeName(const char* name,
   1090                                        ResTable_config* out)
   1091 {
   1092     if (strcmp(name, kWildcardName) == 0) {
   1093         if (out) out->uiMode =
   1094                 (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
   1095                 | ResTable_config::UI_MODE_TYPE_ANY;
   1096         return true;
   1097     } else if (strcmp(name, "desk") == 0) {
   1098       if (out) out->uiMode =
   1099               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
   1100               | ResTable_config::UI_MODE_TYPE_DESK;
   1101         return true;
   1102     } else if (strcmp(name, "car") == 0) {
   1103       if (out) out->uiMode =
   1104               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
   1105               | ResTable_config::UI_MODE_TYPE_CAR;
   1106         return true;
   1107     } else if (strcmp(name, "television") == 0) {
   1108       if (out) out->uiMode =
   1109               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
   1110               | ResTable_config::UI_MODE_TYPE_TELEVISION;
   1111         return true;
   1112     } else if (strcmp(name, "appliance") == 0) {
   1113       if (out) out->uiMode =
   1114               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
   1115               | ResTable_config::UI_MODE_TYPE_APPLIANCE;
   1116         return true;
   1117     }
   1118 
   1119     return false;
   1120 }
   1121 
   1122 bool AaptGroupEntry::getUiModeNightName(const char* name,
   1123                                           ResTable_config* out)
   1124 {
   1125     if (strcmp(name, kWildcardName) == 0) {
   1126         if (out) out->uiMode =
   1127                 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
   1128                 | ResTable_config::UI_MODE_NIGHT_ANY;
   1129         return true;
   1130     } else if (strcmp(name, "night") == 0) {
   1131         if (out) out->uiMode =
   1132                 (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
   1133                 | ResTable_config::UI_MODE_NIGHT_YES;
   1134         return true;
   1135     } else if (strcmp(name, "notnight") == 0) {
   1136       if (out) out->uiMode =
   1137               (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
   1138               | ResTable_config::UI_MODE_NIGHT_NO;
   1139         return true;
   1140     }
   1141 
   1142     return false;
   1143 }
   1144 
   1145 bool AaptGroupEntry::getDensityName(const char* name,
   1146                                     ResTable_config* out)
   1147 {
   1148     if (strcmp(name, kWildcardName) == 0) {
   1149         if (out) out->density = ResTable_config::DENSITY_DEFAULT;
   1150         return true;
   1151     }
   1152 
   1153     if (strcmp(name, "nodpi") == 0) {
   1154         if (out) out->density = ResTable_config::DENSITY_NONE;
   1155         return true;
   1156     }
   1157 
   1158     if (strcmp(name, "ldpi") == 0) {
   1159         if (out) out->density = ResTable_config::DENSITY_LOW;
   1160         return true;
   1161     }
   1162 
   1163     if (strcmp(name, "mdpi") == 0) {
   1164         if (out) out->density = ResTable_config::DENSITY_MEDIUM;
   1165         return true;
   1166     }
   1167 
   1168     if (strcmp(name, "tvdpi") == 0) {
   1169         if (out) out->density = ResTable_config::DENSITY_TV;
   1170         return true;
   1171     }
   1172 
   1173     if (strcmp(name, "hdpi") == 0) {
   1174         if (out) out->density = ResTable_config::DENSITY_HIGH;
   1175         return true;
   1176     }
   1177 
   1178     if (strcmp(name, "xhdpi") == 0) {
   1179         if (out) out->density = ResTable_config::DENSITY_XHIGH;
   1180         return true;
   1181     }
   1182 
   1183     if (strcmp(name, "xxhdpi") == 0) {
   1184         if (out) out->density = ResTable_config::DENSITY_XXHIGH;
   1185         return true;
   1186     }
   1187 
   1188     if (strcmp(name, "xxxhdpi") == 0) {
   1189         if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
   1190         return true;
   1191     }
   1192 
   1193     char* c = (char*)name;
   1194     while (*c >= '0' && *c <= '9') {
   1195         c++;
   1196     }
   1197 
   1198     // check that we have 'dpi' after the last digit.
   1199     if (toupper(c[0]) != 'D' ||
   1200             toupper(c[1]) != 'P' ||
   1201             toupper(c[2]) != 'I' ||
   1202             c[3] != 0) {
   1203         return false;
   1204     }
   1205 
   1206     // temporarily replace the first letter with \0 to
   1207     // use atoi.
   1208     char tmp = c[0];
   1209     c[0] = '\0';
   1210 
   1211     int d = atoi(name);
   1212     c[0] = tmp;
   1213 
   1214     if (d != 0) {
   1215         if (out) out->density = d;
   1216         return true;
   1217     }
   1218 
   1219     return false;
   1220 }
   1221 
   1222 bool AaptGroupEntry::getTouchscreenName(const char* name,
   1223                                         ResTable_config* out)
   1224 {
   1225     if (strcmp(name, kWildcardName) == 0) {
   1226         if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
   1227         return true;
   1228     } else if (strcmp(name, "notouch") == 0) {
   1229         if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
   1230         return true;
   1231     } else if (strcmp(name, "stylus") == 0) {
   1232         if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
   1233         return true;
   1234     } else if (strcmp(name, "finger") == 0) {
   1235         if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
   1236         return true;
   1237     }
   1238 
   1239     return false;
   1240 }
   1241 
   1242 bool AaptGroupEntry::getKeysHiddenName(const char* name,
   1243                                        ResTable_config* out)
   1244 {
   1245     uint8_t mask = 0;
   1246     uint8_t value = 0;
   1247     if (strcmp(name, kWildcardName) == 0) {
   1248         mask = ResTable_config::MASK_KEYSHIDDEN;
   1249         value = ResTable_config::KEYSHIDDEN_ANY;
   1250     } else if (strcmp(name, "keysexposed") == 0) {
   1251         mask = ResTable_config::MASK_KEYSHIDDEN;
   1252         value = ResTable_config::KEYSHIDDEN_NO;
   1253     } else if (strcmp(name, "keyshidden") == 0) {
   1254         mask = ResTable_config::MASK_KEYSHIDDEN;
   1255         value = ResTable_config::KEYSHIDDEN_YES;
   1256     } else if (strcmp(name, "keyssoft") == 0) {
   1257         mask = ResTable_config::MASK_KEYSHIDDEN;
   1258         value = ResTable_config::KEYSHIDDEN_SOFT;
   1259     }
   1260 
   1261     if (mask != 0) {
   1262         if (out) out->inputFlags = (out->inputFlags&~mask) | value;
   1263         return true;
   1264     }
   1265 
   1266     return false;
   1267 }
   1268 
   1269 bool AaptGroupEntry::getKeyboardName(const char* name,
   1270                                         ResTable_config* out)
   1271 {
   1272     if (strcmp(name, kWildcardName) == 0) {
   1273         if (out) out->keyboard = out->KEYBOARD_ANY;
   1274         return true;
   1275     } else if (strcmp(name, "nokeys") == 0) {
   1276         if (out) out->keyboard = out->KEYBOARD_NOKEYS;
   1277         return true;
   1278     } else if (strcmp(name, "qwerty") == 0) {
   1279         if (out) out->keyboard = out->KEYBOARD_QWERTY;
   1280         return true;
   1281     } else if (strcmp(name, "12key") == 0) {
   1282         if (out) out->keyboard = out->KEYBOARD_12KEY;
   1283         return true;
   1284     }
   1285 
   1286     return false;
   1287 }
   1288 
   1289 bool AaptGroupEntry::getNavHiddenName(const char* name,
   1290                                        ResTable_config* out)
   1291 {
   1292     uint8_t mask = 0;
   1293     uint8_t value = 0;
   1294     if (strcmp(name, kWildcardName) == 0) {
   1295         mask = ResTable_config::MASK_NAVHIDDEN;
   1296         value = ResTable_config::NAVHIDDEN_ANY;
   1297     } else if (strcmp(name, "navexposed") == 0) {
   1298         mask = ResTable_config::MASK_NAVHIDDEN;
   1299         value = ResTable_config::NAVHIDDEN_NO;
   1300     } else if (strcmp(name, "navhidden") == 0) {
   1301         mask = ResTable_config::MASK_NAVHIDDEN;
   1302         value = ResTable_config::NAVHIDDEN_YES;
   1303     }
   1304 
   1305     if (mask != 0) {
   1306         if (out) out->inputFlags = (out->inputFlags&~mask) | value;
   1307         return true;
   1308     }
   1309 
   1310     return false;
   1311 }
   1312 
   1313 bool AaptGroupEntry::getNavigationName(const char* name,
   1314                                      ResTable_config* out)
   1315 {
   1316     if (strcmp(name, kWildcardName) == 0) {
   1317         if (out) out->navigation = out->NAVIGATION_ANY;
   1318         return true;
   1319     } else if (strcmp(name, "nonav") == 0) {
   1320         if (out) out->navigation = out->NAVIGATION_NONAV;
   1321         return true;
   1322     } else if (strcmp(name, "dpad") == 0) {
   1323         if (out) out->navigation = out->NAVIGATION_DPAD;
   1324         return true;
   1325     } else if (strcmp(name, "trackball") == 0) {
   1326         if (out) out->navigation = out->NAVIGATION_TRACKBALL;
   1327         return true;
   1328     } else if (strcmp(name, "wheel") == 0) {
   1329         if (out) out->navigation = out->NAVIGATION_WHEEL;
   1330         return true;
   1331     }
   1332 
   1333     return false;
   1334 }
   1335 
   1336 bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
   1337 {
   1338     if (strcmp(name, kWildcardName) == 0) {
   1339         if (out) {
   1340             out->screenWidth = out->SCREENWIDTH_ANY;
   1341             out->screenHeight = out->SCREENHEIGHT_ANY;
   1342         }
   1343         return true;
   1344     }
   1345 
   1346     const char* x = name;
   1347     while (*x >= '0' && *x <= '9') x++;
   1348     if (x == name || *x != 'x') return false;
   1349     String8 xName(name, x-name);
   1350     x++;
   1351 
   1352     const char* y = x;
   1353     while (*y >= '0' && *y <= '9') y++;
   1354     if (y == name || *y != 0) return false;
   1355     String8 yName(x, y-x);
   1356 
   1357     uint16_t w = (uint16_t)atoi(xName.string());
   1358     uint16_t h = (uint16_t)atoi(yName.string());
   1359     if (w < h) {
   1360         return false;
   1361     }
   1362 
   1363     if (out) {
   1364         out->screenWidth = w;
   1365         out->screenHeight = h;
   1366     }
   1367 
   1368     return true;
   1369 }
   1370 
   1371 bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
   1372 {
   1373     if (strcmp(name, kWildcardName) == 0) {
   1374         if (out) {
   1375             out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
   1376         }
   1377         return true;
   1378     }
   1379 
   1380     if (*name != 's') return false;
   1381     name++;
   1382     if (*name != 'w') return false;
   1383     name++;
   1384     const char* x = name;
   1385     while (*x >= '0' && *x <= '9') x++;
   1386     if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
   1387     String8 xName(name, x-name);
   1388 
   1389     if (out) {
   1390         out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
   1391     }
   1392 
   1393     return true;
   1394 }
   1395 
   1396 bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
   1397 {
   1398     if (strcmp(name, kWildcardName) == 0) {
   1399         if (out) {
   1400             out->screenWidthDp = out->SCREENWIDTH_ANY;
   1401         }
   1402         return true;
   1403     }
   1404 
   1405     if (*name != 'w') return false;
   1406     name++;
   1407     const char* x = name;
   1408     while (*x >= '0' && *x <= '9') x++;
   1409     if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
   1410     String8 xName(name, x-name);
   1411 
   1412     if (out) {
   1413         out->screenWidthDp = (uint16_t)atoi(xName.string());
   1414     }
   1415 
   1416     return true;
   1417 }
   1418 
   1419 bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
   1420 {
   1421     if (strcmp(name, kWildcardName) == 0) {
   1422         if (out) {
   1423             out->screenHeightDp = out->SCREENWIDTH_ANY;
   1424         }
   1425         return true;
   1426     }
   1427 
   1428     if (*name != 'h') return false;
   1429     name++;
   1430     const char* x = name;
   1431     while (*x >= '0' && *x <= '9') x++;
   1432     if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
   1433     String8 xName(name, x-name);
   1434 
   1435     if (out) {
   1436         out->screenHeightDp = (uint16_t)atoi(xName.string());
   1437     }
   1438 
   1439     return true;
   1440 }
   1441 
   1442 bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
   1443 {
   1444     if (strcmp(name, kWildcardName) == 0) {
   1445         if (out) {
   1446             out->sdkVersion = out->SDKVERSION_ANY;
   1447             out->minorVersion = out->MINORVERSION_ANY;
   1448         }
   1449         return true;
   1450     }
   1451 
   1452     if (*name != 'v') {
   1453         return false;
   1454     }
   1455 
   1456     name++;
   1457     const char* s = name;
   1458     while (*s >= '0' && *s <= '9') s++;
   1459     if (s == name || *s != 0) return false;
   1460     String8 sdkName(name, s-name);
   1461 
   1462     if (out) {
   1463         out->sdkVersion = (uint16_t)atoi(sdkName.string());
   1464         out->minorVersion = 0;
   1465     }
   1466 
   1467     return true;
   1468 }
   1469 
   1470 int AaptGroupEntry::compare(const AaptGroupEntry& o) const
   1471 {
   1472     int v = mcc.compare(o.mcc);
   1473     if (v == 0) v = mnc.compare(o.mnc);
   1474     if (v == 0) v = locale.compare(o.locale);
   1475     if (v == 0) v = layoutDirection.compare(o.layoutDirection);
   1476     if (v == 0) v = vendor.compare(o.vendor);
   1477     if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
   1478     if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
   1479     if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
   1480     if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
   1481     if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
   1482     if (v == 0) v = orientation.compare(o.orientation);
   1483     if (v == 0) v = uiModeType.compare(o.uiModeType);
   1484     if (v == 0) v = uiModeNight.compare(o.uiModeNight);
   1485     if (v == 0) v = density.compare(o.density);
   1486     if (v == 0) v = touchscreen.compare(o.touchscreen);
   1487     if (v == 0) v = keysHidden.compare(o.keysHidden);
   1488     if (v == 0) v = keyboard.compare(o.keyboard);
   1489     if (v == 0) v = navHidden.compare(o.navHidden);
   1490     if (v == 0) v = navigation.compare(o.navigation);
   1491     if (v == 0) v = screenSize.compare(o.screenSize);
   1492     if (v == 0) v = version.compare(o.version);
   1493     return v;
   1494 }
   1495 
   1496 const ResTable_config& AaptGroupEntry::toParams() const
   1497 {
   1498     if (!mParamsChanged) {
   1499         return mParams;
   1500     }
   1501 
   1502     mParamsChanged = false;
   1503     ResTable_config& params(mParams);
   1504     memset(&params, 0, sizeof(params));
   1505     getMccName(mcc.string(), &params);
   1506     getMncName(mnc.string(), &params);
   1507     getLocaleName(locale.string(), &params);
   1508     getLayoutDirectionName(layoutDirection.string(), &params);
   1509     getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
   1510     getScreenWidthDpName(screenWidthDp.string(), &params);
   1511     getScreenHeightDpName(screenHeightDp.string(), &params);
   1512     getScreenLayoutSizeName(screenLayoutSize.string(), &params);
   1513     getScreenLayoutLongName(screenLayoutLong.string(), &params);
   1514     getOrientationName(orientation.string(), &params);
   1515     getUiModeTypeName(uiModeType.string(), &params);
   1516     getUiModeNightName(uiModeNight.string(), &params);
   1517     getDensityName(density.string(), &params);
   1518     getTouchscreenName(touchscreen.string(), &params);
   1519     getKeysHiddenName(keysHidden.string(), &params);
   1520     getKeyboardName(keyboard.string(), &params);
   1521     getNavHiddenName(navHidden.string(), &params);
   1522     getNavigationName(navigation.string(), &params);
   1523     getScreenSizeName(screenSize.string(), &params);
   1524     getVersionName(version.string(), &params);
   1525 
   1526     // Fix up version number based on specified parameters.
   1527     int minSdk = 0;
   1528     if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
   1529             || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
   1530             || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
   1531         minSdk = SDK_HONEYCOMB_MR2;
   1532     } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
   1533                 != ResTable_config::UI_MODE_TYPE_ANY
   1534             ||  (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
   1535                 != ResTable_config::UI_MODE_NIGHT_ANY) {
   1536         minSdk = SDK_FROYO;
   1537     } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
   1538                 != ResTable_config::SCREENSIZE_ANY
   1539             ||  (params.screenLayout&ResTable_config::MASK_SCREENLONG)
   1540                 != ResTable_config::SCREENLONG_ANY
   1541             || params.density != ResTable_config::DENSITY_DEFAULT) {
   1542         minSdk = SDK_DONUT;
   1543     }
   1544 
   1545     if (minSdk > params.sdkVersion) {
   1546         params.sdkVersion = minSdk;
   1547     }
   1548 
   1549     return params;
   1550 }
   1551 
   1552 // =========================================================================
   1553 // =========================================================================
   1554 // =========================================================================
   1555 
   1556 void* AaptFile::editData(size_t size)
   1557 {
   1558     if (size <= mBufferSize) {
   1559         mDataSize = size;
   1560         return mData;
   1561     }
   1562     size_t allocSize = (size*3)/2;
   1563     void* buf = realloc(mData, allocSize);
   1564     if (buf == NULL) {
   1565         return NULL;
   1566     }
   1567     mData = buf;
   1568     mDataSize = size;
   1569     mBufferSize = allocSize;
   1570     return buf;
   1571 }
   1572 
   1573 void* AaptFile::editData(size_t* outSize)
   1574 {
   1575     if (outSize) {
   1576         *outSize = mDataSize;
   1577     }
   1578     return mData;
   1579 }
   1580 
   1581 void* AaptFile::padData(size_t wordSize)
   1582 {
   1583     const size_t extra = mDataSize%wordSize;
   1584     if (extra == 0) {
   1585         return mData;
   1586     }
   1587 
   1588     size_t initial = mDataSize;
   1589     void* data = editData(initial+(wordSize-extra));
   1590     if (data != NULL) {
   1591         memset(((uint8_t*)data) + initial, 0, wordSize-extra);
   1592     }
   1593     return data;
   1594 }
   1595 
   1596 status_t AaptFile::writeData(const void* data, size_t size)
   1597 {
   1598     size_t end = mDataSize;
   1599     size_t total = size + end;
   1600     void* buf = editData(total);
   1601     if (buf == NULL) {
   1602         return UNKNOWN_ERROR;
   1603     }
   1604     memcpy(((char*)buf)+end, data, size);
   1605     return NO_ERROR;
   1606 }
   1607 
   1608 void AaptFile::clearData()
   1609 {
   1610     if (mData != NULL) free(mData);
   1611     mData = NULL;
   1612     mDataSize = 0;
   1613     mBufferSize = 0;
   1614 }
   1615 
   1616 String8 AaptFile::getPrintableSource() const
   1617 {
   1618     if (hasData()) {
   1619         String8 name(mGroupEntry.toDirName(String8()));
   1620         name.appendPath(mPath);
   1621         name.append(" #generated");
   1622         return name;
   1623     }
   1624     return mSourceFile;
   1625 }
   1626 
   1627 // =========================================================================
   1628 // =========================================================================
   1629 // =========================================================================
   1630 
   1631 status_t AaptGroup::addFile(const sp<AaptFile>& file)
   1632 {
   1633     if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
   1634         file->mPath = mPath;
   1635         mFiles.add(file->getGroupEntry(), file);
   1636         return NO_ERROR;
   1637     }
   1638 
   1639 #if 0
   1640     printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
   1641             file->getSourceFile().string(),
   1642             file->getGroupEntry().toDirName(String8()).string(),
   1643             mLeaf.string(), mPath.string());
   1644 #endif
   1645 
   1646     SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
   1647                                                getPrintableSource().string());
   1648     return UNKNOWN_ERROR;
   1649 }
   1650 
   1651 void AaptGroup::removeFile(size_t index)
   1652 {
   1653 	mFiles.removeItemsAt(index);
   1654 }
   1655 
   1656 void AaptGroup::print(const String8& prefix) const
   1657 {
   1658     printf("%s%s\n", prefix.string(), getPath().string());
   1659     const size_t N=mFiles.size();
   1660     size_t i;
   1661     for (i=0; i<N; i++) {
   1662         sp<AaptFile> file = mFiles.valueAt(i);
   1663         const AaptGroupEntry& e = file->getGroupEntry();
   1664         if (file->hasData()) {
   1665             printf("%s  Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
   1666                     (int)file->getSize());
   1667         } else {
   1668             printf("%s  Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
   1669                     file->getPrintableSource().string());
   1670         }
   1671         //printf("%s  File Group Entry: %s\n", prefix.string(),
   1672         //        file->getGroupEntry().toDirName(String8()).string());
   1673     }
   1674 }
   1675 
   1676 String8 AaptGroup::getPrintableSource() const
   1677 {
   1678     if (mFiles.size() > 0) {
   1679         // Arbitrarily pull the first source file out of the list.
   1680         return mFiles.valueAt(0)->getPrintableSource();
   1681     }
   1682 
   1683     // Should never hit this case, but to be safe...
   1684     return getPath();
   1685 
   1686 }
   1687 
   1688 // =========================================================================
   1689 // =========================================================================
   1690 // =========================================================================
   1691 
   1692 status_t AaptDir::addFile(const String8& name, const sp<AaptGroup>& file)
   1693 {
   1694     if (mFiles.indexOfKey(name) >= 0) {
   1695         return ALREADY_EXISTS;
   1696     }
   1697     mFiles.add(name, file);
   1698     return NO_ERROR;
   1699 }
   1700 
   1701 status_t AaptDir::addDir(const String8& name, const sp<AaptDir>& dir)
   1702 {
   1703     if (mDirs.indexOfKey(name) >= 0) {
   1704         return ALREADY_EXISTS;
   1705     }
   1706     mDirs.add(name, dir);
   1707     return NO_ERROR;
   1708 }
   1709 
   1710 sp<AaptDir> AaptDir::makeDir(const String8& path)
   1711 {
   1712     String8 name;
   1713     String8 remain = path;
   1714 
   1715     sp<AaptDir> subdir = this;
   1716     while (name = remain.walkPath(&remain), remain != "") {
   1717         subdir = subdir->makeDir(name);
   1718     }
   1719 
   1720     ssize_t i = subdir->mDirs.indexOfKey(name);
   1721     if (i >= 0) {
   1722         return subdir->mDirs.valueAt(i);
   1723     }
   1724     sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
   1725     subdir->mDirs.add(name, dir);
   1726     return dir;
   1727 }
   1728 
   1729 void AaptDir::removeFile(const String8& name)
   1730 {
   1731     mFiles.removeItem(name);
   1732 }
   1733 
   1734 void AaptDir::removeDir(const String8& name)
   1735 {
   1736     mDirs.removeItem(name);
   1737 }
   1738 
   1739 status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
   1740 {
   1741     sp<AaptGroup> group;
   1742     if (mFiles.indexOfKey(leafName) >= 0) {
   1743         group = mFiles.valueFor(leafName);
   1744     } else {
   1745         group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
   1746         mFiles.add(leafName, group);
   1747     }
   1748 
   1749     return group->addFile(file);
   1750 }
   1751 
   1752 ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
   1753                             const AaptGroupEntry& kind, const String8& resType,
   1754                             sp<FilePathStore>& fullResPaths)
   1755 {
   1756     Vector<String8> fileNames;
   1757     {
   1758         DIR* dir = NULL;
   1759 
   1760         dir = opendir(srcDir.string());
   1761         if (dir == NULL) {
   1762             fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
   1763             return UNKNOWN_ERROR;
   1764         }
   1765 
   1766         /*
   1767          * Slurp the filenames out of the directory.
   1768          */
   1769         while (1) {
   1770             struct dirent* entry;
   1771 
   1772             entry = readdir(dir);
   1773             if (entry == NULL)
   1774                 break;
   1775 
   1776             if (isHidden(srcDir.string(), entry->d_name))
   1777                 continue;
   1778 
   1779             String8 name(entry->d_name);
   1780             fileNames.add(name);
   1781             // Add fully qualified path for dependency purposes
   1782             // if we're collecting them
   1783             if (fullResPaths != NULL) {
   1784                 fullResPaths->add(srcDir.appendPathCopy(name));
   1785             }
   1786         }
   1787         closedir(dir);
   1788     }
   1789 
   1790     ssize_t count = 0;
   1791 
   1792     /*
   1793      * Stash away the files and recursively descend into subdirectories.
   1794      */
   1795     const size_t N = fileNames.size();
   1796     size_t i;
   1797     for (i = 0; i < N; i++) {
   1798         String8 pathName(srcDir);
   1799         FileType type;
   1800 
   1801         pathName.appendPath(fileNames[i].string());
   1802         type = getFileType(pathName.string());
   1803         if (type == kFileTypeDirectory) {
   1804             sp<AaptDir> subdir;
   1805             bool notAdded = false;
   1806             if (mDirs.indexOfKey(fileNames[i]) >= 0) {
   1807                 subdir = mDirs.valueFor(fileNames[i]);
   1808             } else {
   1809                 subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
   1810                 notAdded = true;
   1811             }
   1812             ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
   1813                                                 resType, fullResPaths);
   1814             if (res < NO_ERROR) {
   1815                 return res;
   1816             }
   1817             if (res > 0 && notAdded) {
   1818                 mDirs.add(fileNames[i], subdir);
   1819             }
   1820             count += res;
   1821         } else if (type == kFileTypeRegular) {
   1822             sp<AaptFile> file = new AaptFile(pathName, kind, resType);
   1823             status_t err = addLeafFile(fileNames[i], file);
   1824             if (err != NO_ERROR) {
   1825                 return err;
   1826             }
   1827 
   1828             count++;
   1829 
   1830         } else {
   1831             if (bundle->getVerbose())
   1832                 printf("   (ignoring non-file/dir '%s')\n", pathName.string());
   1833         }
   1834     }
   1835 
   1836     return count;
   1837 }
   1838 
   1839 status_t AaptDir::validate() const
   1840 {
   1841     const size_t NF = mFiles.size();
   1842     const size_t ND = mDirs.size();
   1843     size_t i;
   1844     for (i = 0; i < NF; i++) {
   1845         if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
   1846             SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
   1847                     "Invalid filename.  Unable to add.");
   1848             return UNKNOWN_ERROR;
   1849         }
   1850 
   1851         size_t j;
   1852         for (j = i+1; j < NF; j++) {
   1853             if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
   1854                            mFiles.valueAt(j)->getLeaf().string()) == 0) {
   1855                 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
   1856                         "File is case-insensitive equivalent to: %s",
   1857                         mFiles.valueAt(j)->getPrintableSource().string());
   1858                 return UNKNOWN_ERROR;
   1859             }
   1860 
   1861             // TODO: if ".gz", check for non-.gz; if non-, check for ".gz"
   1862             // (this is mostly caught by the "marked" stuff, below)
   1863         }
   1864 
   1865         for (j = 0; j < ND; j++) {
   1866             if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
   1867                            mDirs.valueAt(j)->getLeaf().string()) == 0) {
   1868                 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
   1869                         "File conflicts with dir from: %s",
   1870                         mDirs.valueAt(j)->getPrintableSource().string());
   1871                 return UNKNOWN_ERROR;
   1872             }
   1873         }
   1874     }
   1875 
   1876     for (i = 0; i < ND; i++) {
   1877         if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
   1878             SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
   1879                     "Invalid directory name, unable to add.");
   1880             return UNKNOWN_ERROR;
   1881         }
   1882 
   1883         size_t j;
   1884         for (j = i+1; j < ND; j++) {
   1885             if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
   1886                            mDirs.valueAt(j)->getLeaf().string()) == 0) {
   1887                 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
   1888                         "Directory is case-insensitive equivalent to: %s",
   1889                         mDirs.valueAt(j)->getPrintableSource().string());
   1890                 return UNKNOWN_ERROR;
   1891             }
   1892         }
   1893 
   1894         status_t err = mDirs.valueAt(i)->validate();
   1895         if (err != NO_ERROR) {
   1896             return err;
   1897         }
   1898     }
   1899 
   1900     return NO_ERROR;
   1901 }
   1902 
   1903 void AaptDir::print(const String8& prefix) const
   1904 {
   1905     const size_t ND=getDirs().size();
   1906     size_t i;
   1907     for (i=0; i<ND; i++) {
   1908         getDirs().valueAt(i)->print(prefix);
   1909     }
   1910 
   1911     const size_t NF=getFiles().size();
   1912     for (i=0; i<NF; i++) {
   1913         getFiles().valueAt(i)->print(prefix);
   1914     }
   1915 }
   1916 
   1917 String8 AaptDir::getPrintableSource() const
   1918 {
   1919     if (mFiles.size() > 0) {
   1920         // Arbitrarily pull the first file out of the list as the source dir.
   1921         return mFiles.valueAt(0)->getPrintableSource().getPathDir();
   1922     }
   1923     if (mDirs.size() > 0) {
   1924         // Or arbitrarily pull the first dir out of the list as the source dir.
   1925         return mDirs.valueAt(0)->getPrintableSource().getPathDir();
   1926     }
   1927 
   1928     // Should never hit this case, but to be safe...
   1929     return mPath;
   1930 
   1931 }
   1932 
   1933 // =========================================================================
   1934 // =========================================================================
   1935 // =========================================================================
   1936 
   1937 status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
   1938 {
   1939     status_t err = NO_ERROR;
   1940     size_t N = javaSymbols->mSymbols.size();
   1941     for (size_t i=0; i<N; i++) {
   1942         const String8& name = javaSymbols->mSymbols.keyAt(i);
   1943         const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
   1944         ssize_t pos = mSymbols.indexOfKey(name);
   1945         if (pos < 0) {
   1946             entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
   1947             err = UNKNOWN_ERROR;
   1948             continue;
   1949         }
   1950         //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
   1951         //        i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
   1952         mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
   1953     }
   1954 
   1955     N = javaSymbols->mNestedSymbols.size();
   1956     for (size_t i=0; i<N; i++) {
   1957         const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
   1958         const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
   1959         ssize_t pos = mNestedSymbols.indexOfKey(name);
   1960         if (pos < 0) {
   1961             SourcePos pos;
   1962             pos.error("Java symbol dir %s not defined\n", name.string());
   1963             err = UNKNOWN_ERROR;
   1964             continue;
   1965         }
   1966         //printf("**** applying java symbols in dir %s\n", name.string());
   1967         status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
   1968         if (myerr != NO_ERROR) {
   1969             err = myerr;
   1970         }
   1971     }
   1972 
   1973     return err;
   1974 }
   1975 
   1976 // =========================================================================
   1977 // =========================================================================
   1978 // =========================================================================
   1979 
   1980 AaptAssets::AaptAssets()
   1981     : AaptDir(String8(), String8()),
   1982       mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
   1983 {
   1984 }
   1985 
   1986 const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
   1987     if (mChanged) {
   1988     }
   1989     return mGroupEntries;
   1990 }
   1991 
   1992 status_t AaptAssets::addFile(const String8& name, const sp<AaptGroup>& file)
   1993 {
   1994     mChanged = true;
   1995     return AaptDir::addFile(name, file);
   1996 }
   1997 
   1998 sp<AaptFile> AaptAssets::addFile(
   1999         const String8& filePath, const AaptGroupEntry& entry,
   2000         const String8& srcDir, sp<AaptGroup>* outGroup,
   2001         const String8& resType)
   2002 {
   2003     sp<AaptDir> dir = this;
   2004     sp<AaptGroup> group;
   2005     sp<AaptFile> file;
   2006     String8 root, remain(filePath), partialPath;
   2007     while (remain.length() > 0) {
   2008         root = remain.walkPath(&remain);
   2009         partialPath.appendPath(root);
   2010 
   2011         const String8 rootStr(root);
   2012 
   2013         if (remain.length() == 0) {
   2014             ssize_t i = dir->getFiles().indexOfKey(rootStr);
   2015             if (i >= 0) {
   2016                 group = dir->getFiles().valueAt(i);
   2017             } else {
   2018                 group = new AaptGroup(rootStr, filePath);
   2019                 status_t res = dir->addFile(rootStr, group);
   2020                 if (res != NO_ERROR) {
   2021                     return NULL;
   2022                 }
   2023             }
   2024             file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
   2025             status_t res = group->addFile(file);
   2026             if (res != NO_ERROR) {
   2027                 return NULL;
   2028             }
   2029             break;
   2030 
   2031         } else {
   2032             ssize_t i = dir->getDirs().indexOfKey(rootStr);
   2033             if (i >= 0) {
   2034                 dir = dir->getDirs().valueAt(i);
   2035             } else {
   2036                 sp<AaptDir> subdir = new AaptDir(rootStr, partialPath);
   2037                 status_t res = dir->addDir(rootStr, subdir);
   2038                 if (res != NO_ERROR) {
   2039                     return NULL;
   2040                 }
   2041                 dir = subdir;
   2042             }
   2043         }
   2044     }
   2045 
   2046     mGroupEntries.add(entry);
   2047     if (outGroup) *outGroup = group;
   2048     return file;
   2049 }
   2050 
   2051 void AaptAssets::addResource(const String8& leafName, const String8& path,
   2052                 const sp<AaptFile>& file, const String8& resType)
   2053 {
   2054     sp<AaptDir> res = AaptDir::makeDir(kResString);
   2055     String8 dirname = file->getGroupEntry().toDirName(resType);
   2056     sp<AaptDir> subdir = res->makeDir(dirname);
   2057     sp<AaptGroup> grr = new AaptGroup(leafName, path);
   2058     grr->addFile(file);
   2059 
   2060     subdir->addFile(leafName, grr);
   2061 }
   2062 
   2063 
   2064 ssize_t AaptAssets::slurpFromArgs(Bundle* bundle)
   2065 {
   2066     int count;
   2067     int totalCount = 0;
   2068     FileType type;
   2069     const Vector<const char *>& resDirs = bundle->getResourceSourceDirs();
   2070     const size_t dirCount =resDirs.size();
   2071     sp<AaptAssets> current = this;
   2072 
   2073     const int N = bundle->getFileSpecCount();
   2074 
   2075     /*
   2076      * If a package manifest was specified, include that first.
   2077      */
   2078     if (bundle->getAndroidManifestFile() != NULL) {
   2079         // place at root of zip.
   2080         String8 srcFile(bundle->getAndroidManifestFile());
   2081         addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
   2082                 NULL, String8());
   2083         totalCount++;
   2084     }
   2085 
   2086     /*
   2087      * If a directory of custom assets was supplied, slurp 'em up.
   2088      */
   2089     if (bundle->getAssetSourceDir()) {
   2090         const char* assetDir = bundle->getAssetSourceDir();
   2091 
   2092         FileType type = getFileType(assetDir);
   2093         if (type == kFileTypeNonexistent) {
   2094             fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
   2095             return UNKNOWN_ERROR;
   2096         }
   2097         if (type != kFileTypeDirectory) {
   2098             fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
   2099             return UNKNOWN_ERROR;
   2100         }
   2101 
   2102         String8 assetRoot(assetDir);
   2103         sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
   2104         AaptGroupEntry group;
   2105         count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
   2106                                             String8(), mFullAssetPaths);
   2107         if (count < 0) {
   2108             totalCount = count;
   2109             goto bail;
   2110         }
   2111         if (count > 0) {
   2112             mGroupEntries.add(group);
   2113         }
   2114         totalCount += count;
   2115 
   2116         if (bundle->getVerbose())
   2117             printf("Found %d custom asset file%s in %s\n",
   2118                    count, (count==1) ? "" : "s", assetDir);
   2119     }
   2120 
   2121     /*
   2122      * If a directory of resource-specific assets was supplied, slurp 'em up.
   2123      */
   2124     for (size_t i=0; i<dirCount; i++) {
   2125         const char *res = resDirs[i];
   2126         if (res) {
   2127             type = getFileType(res);
   2128             if (type == kFileTypeNonexistent) {
   2129                 fprintf(stderr, "ERROR: resource directory '%s' does not exist\n", res);
   2130                 return UNKNOWN_ERROR;
   2131             }
   2132             if (type == kFileTypeDirectory) {
   2133                 if (i>0) {
   2134                     sp<AaptAssets> nextOverlay = new AaptAssets();
   2135                     current->setOverlay(nextOverlay);
   2136                     current = nextOverlay;
   2137                     current->setFullResPaths(mFullResPaths);
   2138                 }
   2139                 count = current->slurpResourceTree(bundle, String8(res));
   2140 
   2141                 if (count < 0) {
   2142                     totalCount = count;
   2143                     goto bail;
   2144                 }
   2145                 totalCount += count;
   2146             }
   2147             else {
   2148                 fprintf(stderr, "ERROR: '%s' is not a directory\n", res);
   2149                 return UNKNOWN_ERROR;
   2150             }
   2151         }
   2152 
   2153     }
   2154     /*
   2155      * Now do any additional raw files.
   2156      */
   2157     for (int arg=0; arg<N; arg++) {
   2158         const char* assetDir = bundle->getFileSpecEntry(arg);
   2159 
   2160         FileType type = getFileType(assetDir);
   2161         if (type == kFileTypeNonexistent) {
   2162             fprintf(stderr, "ERROR: input directory '%s' does not exist\n", assetDir);
   2163             return UNKNOWN_ERROR;
   2164         }
   2165         if (type != kFileTypeDirectory) {
   2166             fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
   2167             return UNKNOWN_ERROR;
   2168         }
   2169 
   2170         String8 assetRoot(assetDir);
   2171 
   2172         if (bundle->getVerbose())
   2173             printf("Processing raw dir '%s'\n", (const char*) assetDir);
   2174 
   2175         /*
   2176          * Do a recursive traversal of subdir tree.  We don't make any
   2177          * guarantees about ordering, so we're okay with an inorder search
   2178          * using whatever order the OS happens to hand back to us.
   2179          */
   2180         count = slurpFullTree(bundle, assetRoot, AaptGroupEntry(), String8(), mFullAssetPaths);
   2181         if (count < 0) {
   2182             /* failure; report error and remove archive */
   2183             totalCount = count;
   2184             goto bail;
   2185         }
   2186         totalCount += count;
   2187 
   2188         if (bundle->getVerbose())
   2189             printf("Found %d asset file%s in %s\n",
   2190                    count, (count==1) ? "" : "s", assetDir);
   2191     }
   2192 
   2193     count = validate();
   2194     if (count != NO_ERROR) {
   2195         totalCount = count;
   2196         goto bail;
   2197     }
   2198 
   2199     count = filter(bundle);
   2200     if (count != NO_ERROR) {
   2201         totalCount = count;
   2202         goto bail;
   2203     }
   2204 
   2205 bail:
   2206     return totalCount;
   2207 }
   2208 
   2209 ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
   2210                                     const AaptGroupEntry& kind,
   2211                                     const String8& resType,
   2212                                     sp<FilePathStore>& fullResPaths)
   2213 {
   2214     ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
   2215     if (res > 0) {
   2216         mGroupEntries.add(kind);
   2217     }
   2218 
   2219     return res;
   2220 }
   2221 
   2222 ssize_t AaptAssets::slurpResourceTree(Bundle* bundle, const String8& srcDir)
   2223 {
   2224     ssize_t err = 0;
   2225 
   2226     DIR* dir = opendir(srcDir.string());
   2227     if (dir == NULL) {
   2228         fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
   2229         return UNKNOWN_ERROR;
   2230     }
   2231 
   2232     status_t count = 0;
   2233 
   2234     /*
   2235      * Run through the directory, looking for dirs that match the
   2236      * expected pattern.
   2237      */
   2238     while (1) {
   2239         struct dirent* entry = readdir(dir);
   2240         if (entry == NULL) {
   2241             break;
   2242         }
   2243 
   2244         if (isHidden(srcDir.string(), entry->d_name)) {
   2245             continue;
   2246         }
   2247 
   2248         String8 subdirName(srcDir);
   2249         subdirName.appendPath(entry->d_name);
   2250 
   2251         AaptGroupEntry group;
   2252         String8 resType;
   2253         bool b = group.initFromDirName(entry->d_name, &resType);
   2254         if (!b) {
   2255             fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
   2256                     entry->d_name);
   2257             err = -1;
   2258             continue;
   2259         }
   2260 
   2261         if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
   2262             int maxResInt = atoi(bundle->getMaxResVersion());
   2263             const char *verString = group.getVersionString().string();
   2264             int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
   2265             if (dirVersionInt > maxResInt) {
   2266               fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
   2267               continue;
   2268             }
   2269         }
   2270 
   2271         FileType type = getFileType(subdirName.string());
   2272 
   2273         if (type == kFileTypeDirectory) {
   2274             sp<AaptDir> dir = makeDir(resType);
   2275             ssize_t res = dir->slurpFullTree(bundle, subdirName, group,
   2276                                                 resType, mFullResPaths);
   2277             if (res < 0) {
   2278                 count = res;
   2279                 goto bail;
   2280             }
   2281             if (res > 0) {
   2282                 mGroupEntries.add(group);
   2283                 count += res;
   2284             }
   2285 
   2286             // Only add this directory if we don't already have a resource dir
   2287             // for the current type.  This ensures that we only add the dir once
   2288             // for all configs.
   2289             sp<AaptDir> rdir = resDir(resType);
   2290             if (rdir == NULL) {
   2291                 mResDirs.add(dir);
   2292             }
   2293         } else {
   2294             if (bundle->getVerbose()) {
   2295                 fprintf(stderr, "   (ignoring file '%s')\n", subdirName.string());
   2296             }
   2297         }
   2298     }
   2299 
   2300 bail:
   2301     closedir(dir);
   2302     dir = NULL;
   2303 
   2304     if (err != 0) {
   2305         return err;
   2306     }
   2307     return count;
   2308 }
   2309 
   2310 ssize_t
   2311 AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
   2312 {
   2313     int count = 0;
   2314     SortedVector<AaptGroupEntry> entries;
   2315 
   2316     ZipFile* zip = new ZipFile;
   2317     status_t err = zip->open(filename, ZipFile::kOpenReadOnly);
   2318     if (err != NO_ERROR) {
   2319         fprintf(stderr, "error opening zip file %s\n", filename);
   2320         count = err;
   2321         delete zip;
   2322         return -1;
   2323     }
   2324 
   2325     const int N = zip->getNumEntries();
   2326     for (int i=0; i<N; i++) {
   2327         ZipEntry* entry = zip->getEntryByIndex(i);
   2328         if (entry->getDeleted()) {
   2329             continue;
   2330         }
   2331 
   2332         String8 entryName(entry->getFileName());
   2333 
   2334         String8 dirName = entryName.getPathDir();
   2335         sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
   2336 
   2337         String8 resType;
   2338         AaptGroupEntry kind;
   2339 
   2340         String8 remain;
   2341         if (entryName.walkPath(&remain) == kResourceDir) {
   2342             // these are the resources, pull their type out of the directory name
   2343             kind.initFromDirName(remain.walkPath().string(), &resType);
   2344         } else {
   2345             // these are untyped and don't have an AaptGroupEntry
   2346         }
   2347         if (entries.indexOf(kind) < 0) {
   2348             entries.add(kind);
   2349             mGroupEntries.add(kind);
   2350         }
   2351 
   2352         // use the one from the zip file if they both exist.
   2353         dir->removeFile(entryName.getPathLeaf());
   2354 
   2355         sp<AaptFile> file = new AaptFile(entryName, kind, resType);
   2356         status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
   2357         if (err != NO_ERROR) {
   2358             fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
   2359             count = err;
   2360             goto bail;
   2361         }
   2362         file->setCompressionMethod(entry->getCompressionMethod());
   2363 
   2364 #if 0
   2365         if (entryName == "AndroidManifest.xml") {
   2366             printf("AndroidManifest.xml\n");
   2367         }
   2368         printf("\n\nfile: %s\n", entryName.string());
   2369 #endif
   2370 
   2371         size_t len = entry->getUncompressedLen();
   2372         void* data = zip->uncompress(entry);
   2373         void* buf = file->editData(len);
   2374         memcpy(buf, data, len);
   2375 
   2376 #if 0
   2377         const int OFF = 0;
   2378         const unsigned char* p = (unsigned char*)data;
   2379         const unsigned char* end = p+len;
   2380         p += OFF;
   2381         for (int i=0; i<32 && p < end; i++) {
   2382             printf("0x%03x ", i*0x10 + OFF);
   2383             for (int j=0; j<0x10 && p < end; j++) {
   2384                 printf(" %02x", *p);
   2385                 p++;
   2386             }
   2387             printf("\n");
   2388         }
   2389 #endif
   2390 
   2391         free(data);
   2392 
   2393         count++;
   2394     }
   2395 
   2396 bail:
   2397     delete zip;
   2398     return count;
   2399 }
   2400 
   2401 status_t AaptAssets::filter(Bundle* bundle)
   2402 {
   2403     ResourceFilter reqFilter;
   2404     status_t err = reqFilter.parse(bundle->getConfigurations());
   2405     if (err != NO_ERROR) {
   2406         return err;
   2407     }
   2408 
   2409     ResourceFilter prefFilter;
   2410     err = prefFilter.parse(bundle->getPreferredConfigurations());
   2411     if (err != NO_ERROR) {
   2412         return err;
   2413     }
   2414 
   2415     if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
   2416         return NO_ERROR;
   2417     }
   2418 
   2419     if (bundle->getVerbose()) {
   2420         if (!reqFilter.isEmpty()) {
   2421             printf("Applying required filter: %s\n",
   2422                     bundle->getConfigurations());
   2423         }
   2424         if (!prefFilter.isEmpty()) {
   2425             printf("Applying preferred filter: %s\n",
   2426                     bundle->getPreferredConfigurations());
   2427         }
   2428     }
   2429 
   2430     const Vector<sp<AaptDir> >& resdirs = mResDirs;
   2431     const size_t ND = resdirs.size();
   2432     for (size_t i=0; i<ND; i++) {
   2433         const sp<AaptDir>& dir = resdirs.itemAt(i);
   2434         if (dir->getLeaf() == kValuesDir) {
   2435             // The "value" dir is special since a single file defines
   2436             // multiple resources, so we can not do filtering on the
   2437             // files themselves.
   2438             continue;
   2439         }
   2440         if (dir->getLeaf() == kMipmapDir) {
   2441             // We also skip the "mipmap" directory, since the point of this
   2442             // is to include all densities without stripping.  If you put
   2443             // other configurations in here as well they won't be stripped
   2444             // either...  So don't do that.  Seriously.  What is wrong with you?
   2445             continue;
   2446         }
   2447 
   2448         const size_t NG = dir->getFiles().size();
   2449         for (size_t j=0; j<NG; j++) {
   2450             sp<AaptGroup> grp = dir->getFiles().valueAt(j);
   2451 
   2452             // First remove any configurations we know we don't need.
   2453             for (size_t k=0; k<grp->getFiles().size(); k++) {
   2454                 sp<AaptFile> file = grp->getFiles().valueAt(k);
   2455                 if (k == 0 && grp->getFiles().size() == 1) {
   2456                     // If this is the only file left, we need to keep it.
   2457                     // Otherwise the resource IDs we are using will be inconsistent
   2458                     // with what we get when not stripping.  Sucky, but at least
   2459                     // for now we can rely on the back-end doing another filtering
   2460                     // pass to take this out and leave us with this resource name
   2461                     // containing no entries.
   2462                     continue;
   2463                 }
   2464                 if (file->getPath().getPathExtension() == ".xml") {
   2465                     // We can't remove .xml files at this point, because when
   2466                     // we parse them they may add identifier resources, so
   2467                     // removing them can cause our resource identifiers to
   2468                     // become inconsistent.
   2469                     continue;
   2470                 }
   2471                 const ResTable_config& config(file->getGroupEntry().toParams());
   2472                 if (!reqFilter.match(config)) {
   2473                     if (bundle->getVerbose()) {
   2474                         printf("Pruning unneeded resource: %s\n",
   2475                                 file->getPrintableSource().string());
   2476                     }
   2477                     grp->removeFile(k);
   2478                     k--;
   2479                 }
   2480             }
   2481 
   2482             // Quick check: no preferred filters, nothing more to do.
   2483             if (prefFilter.isEmpty()) {
   2484                 continue;
   2485             }
   2486 
   2487             // Now deal with preferred configurations.
   2488             for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
   2489                 for (size_t k=0; k<grp->getFiles().size(); k++) {
   2490                     sp<AaptFile> file = grp->getFiles().valueAt(k);
   2491                     if (k == 0 && grp->getFiles().size() == 1) {
   2492                         // If this is the only file left, we need to keep it.
   2493                         // Otherwise the resource IDs we are using will be inconsistent
   2494                         // with what we get when not stripping.  Sucky, but at least
   2495                         // for now we can rely on the back-end doing another filtering
   2496                         // pass to take this out and leave us with this resource name
   2497                         // containing no entries.
   2498                         continue;
   2499                     }
   2500                     if (file->getPath().getPathExtension() == ".xml") {
   2501                         // We can't remove .xml files at this point, because when
   2502                         // we parse them they may add identifier resources, so
   2503                         // removing them can cause our resource identifiers to
   2504                         // become inconsistent.
   2505                         continue;
   2506                     }
   2507                     const ResTable_config& config(file->getGroupEntry().toParams());
   2508                     if (!prefFilter.match(axis, config)) {
   2509                         // This is a resource we would prefer not to have.  Check
   2510                         // to see if have a similar variation that we would like
   2511                         // to have and, if so, we can drop it.
   2512                         for (size_t m=0; m<grp->getFiles().size(); m++) {
   2513                             if (m == k) continue;
   2514                             sp<AaptFile> mfile = grp->getFiles().valueAt(m);
   2515                             const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
   2516                             if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
   2517                                 if (prefFilter.match(axis, mconfig)) {
   2518                                     if (bundle->getVerbose()) {
   2519                                         printf("Pruning unneeded resource: %s\n",
   2520                                                 file->getPrintableSource().string());
   2521                                     }
   2522                                     grp->removeFile(k);
   2523                                     k--;
   2524                                     break;
   2525                                 }
   2526                             }
   2527                         }
   2528                     }
   2529                 }
   2530             }
   2531         }
   2532     }
   2533 
   2534     return NO_ERROR;
   2535 }
   2536 
   2537 sp<AaptSymbols> AaptAssets::getSymbolsFor(const String8& name)
   2538 {
   2539     sp<AaptSymbols> sym = mSymbols.valueFor(name);
   2540     if (sym == NULL) {
   2541         sym = new AaptSymbols();
   2542         mSymbols.add(name, sym);
   2543     }
   2544     return sym;
   2545 }
   2546 
   2547 sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
   2548 {
   2549     sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
   2550     if (sym == NULL) {
   2551         sym = new AaptSymbols();
   2552         mJavaSymbols.add(name, sym);
   2553     }
   2554     return sym;
   2555 }
   2556 
   2557 status_t AaptAssets::applyJavaSymbols()
   2558 {
   2559     size_t N = mJavaSymbols.size();
   2560     for (size_t i=0; i<N; i++) {
   2561         const String8& name = mJavaSymbols.keyAt(i);
   2562         const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
   2563         ssize_t pos = mSymbols.indexOfKey(name);
   2564         if (pos < 0) {
   2565             SourcePos pos;
   2566             pos.error("Java symbol dir %s not defined\n", name.string());
   2567             return UNKNOWN_ERROR;
   2568         }
   2569         //printf("**** applying java symbols in dir %s\n", name.string());
   2570         status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
   2571         if (err != NO_ERROR) {
   2572             return err;
   2573         }
   2574     }
   2575 
   2576     return NO_ERROR;
   2577 }
   2578 
   2579 bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
   2580     //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
   2581     //        sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
   2582     //        sym.isJavaSymbol ? 1 : 0);
   2583     if (!mHavePrivateSymbols) return true;
   2584     if (sym.isPublic) return true;
   2585     if (includePrivate && sym.isJavaSymbol) return true;
   2586     return false;
   2587 }
   2588 
   2589 status_t AaptAssets::buildIncludedResources(Bundle* bundle)
   2590 {
   2591     if (!mHaveIncludedAssets) {
   2592         // Add in all includes.
   2593         const Vector<const char*>& incl = bundle->getPackageIncludes();
   2594         const size_t N=incl.size();
   2595         for (size_t i=0; i<N; i++) {
   2596             if (bundle->getVerbose())
   2597                 printf("Including resources from package: %s\n", incl[i]);
   2598             if (!mIncludedAssets.addAssetPath(String8(incl[i]), NULL)) {
   2599                 fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
   2600                         incl[i]);
   2601                 return UNKNOWN_ERROR;
   2602             }
   2603         }
   2604         mHaveIncludedAssets = true;
   2605     }
   2606 
   2607     return NO_ERROR;
   2608 }
   2609 
   2610 status_t AaptAssets::addIncludedResources(const sp<AaptFile>& file)
   2611 {
   2612     const ResTable& res = getIncludedResources();
   2613     // XXX dirty!
   2614     return const_cast<ResTable&>(res).add(file->getData(), file->getSize(), NULL);
   2615 }
   2616 
   2617 const ResTable& AaptAssets::getIncludedResources() const
   2618 {
   2619     return mIncludedAssets.getResources(false);
   2620 }
   2621 
   2622 void AaptAssets::print(const String8& prefix) const
   2623 {
   2624     String8 innerPrefix(prefix);
   2625     innerPrefix.append("  ");
   2626     String8 innerInnerPrefix(innerPrefix);
   2627     innerInnerPrefix.append("  ");
   2628     printf("%sConfigurations:\n", prefix.string());
   2629     const size_t N=mGroupEntries.size();
   2630     for (size_t i=0; i<N; i++) {
   2631         String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
   2632         printf("%s %s\n", prefix.string(),
   2633                 cname != "" ? cname.string() : "(default)");
   2634     }
   2635 
   2636     printf("\n%sFiles:\n", prefix.string());
   2637     AaptDir::print(innerPrefix);
   2638 
   2639     printf("\n%sResource Dirs:\n", prefix.string());
   2640     const Vector<sp<AaptDir> >& resdirs = mResDirs;
   2641     const size_t NR = resdirs.size();
   2642     for (size_t i=0; i<NR; i++) {
   2643         const sp<AaptDir>& d = resdirs.itemAt(i);
   2644         printf("%s  Type %s\n", prefix.string(), d->getLeaf().string());
   2645         d->print(innerInnerPrefix);
   2646     }
   2647 }
   2648 
   2649 sp<AaptDir> AaptAssets::resDir(const String8& name) const
   2650 {
   2651     const Vector<sp<AaptDir> >& resdirs = mResDirs;
   2652     const size_t N = resdirs.size();
   2653     for (size_t i=0; i<N; i++) {
   2654         const sp<AaptDir>& d = resdirs.itemAt(i);
   2655         if (d->getLeaf() == name) {
   2656             return d;
   2657         }
   2658     }
   2659     return NULL;
   2660 }
   2661 
   2662 bool
   2663 valid_symbol_name(const String8& symbol)
   2664 {
   2665     static char const * const KEYWORDS[] = {
   2666         "abstract", "assert", "boolean", "break",
   2667         "byte", "case", "catch", "char", "class", "const", "continue",
   2668         "default", "do", "double", "else", "enum", "extends", "final",
   2669         "finally", "float", "for", "goto", "if", "implements", "import",
   2670         "instanceof", "int", "interface", "long", "native", "new", "package",
   2671         "private", "protected", "public", "return", "short", "static",
   2672         "strictfp", "super", "switch", "synchronized", "this", "throw",
   2673         "throws", "transient", "try", "void", "volatile", "while",
   2674         "true", "false", "null",
   2675         NULL
   2676     };
   2677     const char*const* k = KEYWORDS;
   2678     const char*const s = symbol.string();
   2679     while (*k) {
   2680         if (0 == strcmp(s, *k)) {
   2681             return false;
   2682         }
   2683         k++;
   2684     }
   2685     return true;
   2686 }
   2687