Home | History | Annotate | Download | only in aapt
      1 //
      2 // Copyright 2006 The Android Open Source Project
      3 //
      4 // Android Asset Packaging Tool main entry point.
      5 //
      6 #include "AaptXml.h"
      7 #include "ApkBuilder.h"
      8 #include "Bundle.h"
      9 #include "Images.h"
     10 #include "Main.h"
     11 #include "ResourceFilter.h"
     12 #include "ResourceTable.h"
     13 #include "XMLNode.h"
     14 
     15 #include <utils/Errors.h>
     16 #include <utils/KeyedVector.h>
     17 #include <utils/List.h>
     18 #include <utils/Log.h>
     19 #include <utils/SortedVector.h>
     20 #include <utils/threads.h>
     21 #include <utils/Vector.h>
     22 
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 
     26 #include <iostream>
     27 #include <string>
     28 #include <sstream>
     29 
     30 using namespace android;
     31 
     32 #ifndef AAPT_VERSION
     33     #define AAPT_VERSION ""
     34 #endif
     35 
     36 /*
     37  * Show version info.  All the cool kids do it.
     38  */
     39 int doVersion(Bundle* bundle)
     40 {
     41     if (bundle->getFileSpecCount() != 0) {
     42         printf("(ignoring extra arguments)\n");
     43     }
     44     printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
     45 
     46     return 0;
     47 }
     48 
     49 
     50 /*
     51  * Open the file read only.  The call fails if the file doesn't exist.
     52  *
     53  * Returns NULL on failure.
     54  */
     55 ZipFile* openReadOnly(const char* fileName)
     56 {
     57     ZipFile* zip;
     58     status_t result;
     59 
     60     zip = new ZipFile;
     61     result = zip->open(fileName, ZipFile::kOpenReadOnly);
     62     if (result != NO_ERROR) {
     63         if (result == NAME_NOT_FOUND) {
     64             fprintf(stderr, "ERROR: '%s' not found\n", fileName);
     65         } else if (result == PERMISSION_DENIED) {
     66             fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
     67         } else {
     68             fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
     69                 fileName);
     70         }
     71         delete zip;
     72         return NULL;
     73     }
     74 
     75     return zip;
     76 }
     77 
     78 /*
     79  * Open the file read-write.  The file will be created if it doesn't
     80  * already exist and "okayToCreate" is set.
     81  *
     82  * Returns NULL on failure.
     83  */
     84 ZipFile* openReadWrite(const char* fileName, bool okayToCreate)
     85 {
     86     ZipFile* zip = NULL;
     87     status_t result;
     88     int flags;
     89 
     90     flags = ZipFile::kOpenReadWrite;
     91     if (okayToCreate) {
     92         flags |= ZipFile::kOpenCreate;
     93     }
     94 
     95     zip = new ZipFile;
     96     result = zip->open(fileName, flags);
     97     if (result != NO_ERROR) {
     98         delete zip;
     99         zip = NULL;
    100         goto bail;
    101     }
    102 
    103 bail:
    104     return zip;
    105 }
    106 
    107 
    108 /*
    109  * Return a short string describing the compression method.
    110  */
    111 const char* compressionName(int method)
    112 {
    113     if (method == ZipEntry::kCompressStored) {
    114         return "Stored";
    115     } else if (method == ZipEntry::kCompressDeflated) {
    116         return "Deflated";
    117     } else {
    118         return "Unknown";
    119     }
    120 }
    121 
    122 /*
    123  * Return the percent reduction in size (0% == no compression).
    124  */
    125 int calcPercent(long uncompressedLen, long compressedLen)
    126 {
    127     if (!uncompressedLen) {
    128         return 0;
    129     } else {
    130         return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
    131     }
    132 }
    133 
    134 /*
    135  * Handle the "list" command, which can be a simple file dump or
    136  * a verbose listing.
    137  *
    138  * The verbose listing closely matches the output of the Info-ZIP "unzip"
    139  * command.
    140  */
    141 int doList(Bundle* bundle)
    142 {
    143     int result = 1;
    144     ZipFile* zip = NULL;
    145     const ZipEntry* entry;
    146     long totalUncLen, totalCompLen;
    147     const char* zipFileName;
    148 
    149     if (bundle->getFileSpecCount() != 1) {
    150         fprintf(stderr, "ERROR: specify zip file name (only)\n");
    151         goto bail;
    152     }
    153     zipFileName = bundle->getFileSpecEntry(0);
    154 
    155     zip = openReadOnly(zipFileName);
    156     if (zip == NULL) {
    157         goto bail;
    158     }
    159 
    160     int count, i;
    161 
    162     if (bundle->getVerbose()) {
    163         printf("Archive:  %s\n", zipFileName);
    164         printf(
    165             " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
    166         printf(
    167             "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
    168     }
    169 
    170     totalUncLen = totalCompLen = 0;
    171 
    172     count = zip->getNumEntries();
    173     for (i = 0; i < count; i++) {
    174         entry = zip->getEntryByIndex(i);
    175         if (bundle->getVerbose()) {
    176             char dateBuf[32];
    177             time_t when;
    178 
    179             when = entry->getModWhen();
    180             strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
    181                 localtime(&when));
    182 
    183             printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
    184                 (long) entry->getUncompressedLen(),
    185                 compressionName(entry->getCompressionMethod()),
    186                 (long) entry->getCompressedLen(),
    187                 calcPercent(entry->getUncompressedLen(),
    188                             entry->getCompressedLen()),
    189                 (size_t) entry->getLFHOffset(),
    190                 dateBuf,
    191                 entry->getCRC32(),
    192                 entry->getFileName());
    193         } else {
    194             printf("%s\n", entry->getFileName());
    195         }
    196 
    197         totalUncLen += entry->getUncompressedLen();
    198         totalCompLen += entry->getCompressedLen();
    199     }
    200 
    201     if (bundle->getVerbose()) {
    202         printf(
    203         "--------          -------  ---                            -------\n");
    204         printf("%8ld          %7ld  %2d%%                            %d files\n",
    205             totalUncLen,
    206             totalCompLen,
    207             calcPercent(totalUncLen, totalCompLen),
    208             zip->getNumEntries());
    209     }
    210 
    211     if (bundle->getAndroidList()) {
    212         AssetManager assets;
    213         if (!assets.addAssetPath(String8(zipFileName), NULL)) {
    214             fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
    215             goto bail;
    216         }
    217 
    218         const ResTable& res = assets.getResources(false);
    219         if (&res == NULL) {
    220             printf("\nNo resource table found.\n");
    221         } else {
    222 #ifndef HAVE_ANDROID_OS
    223             printf("\nResource table:\n");
    224             res.print(false);
    225 #endif
    226         }
    227 
    228         Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
    229                                                    Asset::ACCESS_BUFFER);
    230         if (manifestAsset == NULL) {
    231             printf("\nNo AndroidManifest.xml found.\n");
    232         } else {
    233             printf("\nAndroid manifest:\n");
    234             ResXMLTree tree;
    235             tree.setTo(manifestAsset->getBuffer(true),
    236                        manifestAsset->getLength());
    237             printXMLBlock(&tree);
    238         }
    239         delete manifestAsset;
    240     }
    241 
    242     result = 0;
    243 
    244 bail:
    245     delete zip;
    246     return result;
    247 }
    248 
    249 static void printResolvedResourceAttribute(const ResTable& resTable, const ResXMLTree& tree,
    250         uint32_t attrRes, String8 attrLabel, String8* outError)
    251 {
    252     Res_value value;
    253     AaptXml::getResolvedResourceAttribute(resTable, tree, attrRes, &value, outError);
    254     if (*outError != "") {
    255         *outError = "error print resolved resource attribute";
    256         return;
    257     }
    258     if (value.dataType == Res_value::TYPE_STRING) {
    259         String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
    260         printf("%s='%s'", attrLabel.string(),
    261                 ResTable::normalizeForOutput(result.string()).string());
    262     } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
    263             value.dataType <= Res_value::TYPE_LAST_INT) {
    264         printf("%s='%d'", attrLabel.string(), value.data);
    265     } else {
    266         printf("%s='0x%x'", attrLabel.string(), (int)value.data);
    267     }
    268 }
    269 
    270 // These are attribute resource constants for the platform, as found
    271 // in android.R.attr
    272 enum {
    273     LABEL_ATTR = 0x01010001,
    274     ICON_ATTR = 0x01010002,
    275     NAME_ATTR = 0x01010003,
    276     PERMISSION_ATTR = 0x01010006,
    277     EXPORTED_ATTR = 0x01010010,
    278     GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
    279     RESOURCE_ATTR = 0x01010025,
    280     DEBUGGABLE_ATTR = 0x0101000f,
    281     VALUE_ATTR = 0x01010024,
    282     VERSION_CODE_ATTR = 0x0101021b,
    283     VERSION_NAME_ATTR = 0x0101021c,
    284     SCREEN_ORIENTATION_ATTR = 0x0101001e,
    285     MIN_SDK_VERSION_ATTR = 0x0101020c,
    286     MAX_SDK_VERSION_ATTR = 0x01010271,
    287     REQ_TOUCH_SCREEN_ATTR = 0x01010227,
    288     REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
    289     REQ_HARD_KEYBOARD_ATTR = 0x01010229,
    290     REQ_NAVIGATION_ATTR = 0x0101022a,
    291     REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
    292     TARGET_SDK_VERSION_ATTR = 0x01010270,
    293     TEST_ONLY_ATTR = 0x01010272,
    294     ANY_DENSITY_ATTR = 0x0101026c,
    295     GL_ES_VERSION_ATTR = 0x01010281,
    296     SMALL_SCREEN_ATTR = 0x01010284,
    297     NORMAL_SCREEN_ATTR = 0x01010285,
    298     LARGE_SCREEN_ATTR = 0x01010286,
    299     XLARGE_SCREEN_ATTR = 0x010102bf,
    300     REQUIRED_ATTR = 0x0101028e,
    301     INSTALL_LOCATION_ATTR = 0x010102b7,
    302     SCREEN_SIZE_ATTR = 0x010102ca,
    303     SCREEN_DENSITY_ATTR = 0x010102cb,
    304     REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
    305     COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
    306     LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
    307     PUBLIC_KEY_ATTR = 0x010103a6,
    308     CATEGORY_ATTR = 0x010103e8,
    309     BANNER_ATTR = 0x10103f2,
    310     ISGAME_ATTR = 0x10103f4,
    311 };
    312 
    313 String8 getComponentName(String8 &pkgName, String8 &componentName) {
    314     ssize_t idx = componentName.find(".");
    315     String8 retStr(pkgName);
    316     if (idx == 0) {
    317         retStr += componentName;
    318     } else if (idx < 0) {
    319         retStr += ".";
    320         retStr += componentName;
    321     } else {
    322         return componentName;
    323     }
    324     return retStr;
    325 }
    326 
    327 static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
    328     size_t len;
    329     ResXMLTree::event_code_t code;
    330     int depth = 0;
    331     bool first = true;
    332     printf("compatible-screens:");
    333     while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
    334         if (code == ResXMLTree::END_TAG) {
    335             depth--;
    336             if (depth < 0) {
    337                 break;
    338             }
    339             continue;
    340         }
    341         if (code != ResXMLTree::START_TAG) {
    342             continue;
    343         }
    344         depth++;
    345         const char16_t* ctag16 = tree.getElementName(&len);
    346         if (ctag16 == NULL) {
    347             *outError = "failed to get XML element name (bad string pool)";
    348             return;
    349         }
    350         String8 tag(ctag16);
    351         if (tag == "screen") {
    352             int32_t screenSize = AaptXml::getIntegerAttribute(tree,
    353                     SCREEN_SIZE_ATTR);
    354             int32_t screenDensity = AaptXml::getIntegerAttribute(tree,
    355                     SCREEN_DENSITY_ATTR);
    356             if (screenSize > 0 && screenDensity > 0) {
    357                 if (!first) {
    358                     printf(",");
    359                 }
    360                 first = false;
    361                 printf("'%d/%d'", screenSize, screenDensity);
    362             }
    363         }
    364     }
    365     printf("\n");
    366 }
    367 
    368 static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
    369     printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
    370     if (maxSdkVersion != -1) {
    371          printf(" maxSdkVersion='%d'", maxSdkVersion);
    372     }
    373     printf("\n");
    374 
    375     if (optional) {
    376         printf("optional-permission: name='%s'",
    377                 ResTable::normalizeForOutput(name.string()).string());
    378         if (maxSdkVersion != -1) {
    379             printf(" maxSdkVersion='%d'", maxSdkVersion);
    380         }
    381         printf("\n");
    382     }
    383 }
    384 
    385 static void printUsesImpliedPermission(const String8& name, const String8& reason) {
    386     printf("uses-implied-permission: name='%s' reason='%s'\n",
    387             ResTable::normalizeForOutput(name.string()).string(),
    388             ResTable::normalizeForOutput(reason.string()).string());
    389 }
    390 
    391 Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
    392         String8 *outError = NULL)
    393 {
    394     Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
    395     if (aidAsset == NULL) {
    396         if (outError != NULL) *outError = "xml resource does not exist";
    397         return Vector<String8>();
    398     }
    399 
    400     const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
    401 
    402     bool withinApduService = false;
    403     Vector<String8> categories;
    404 
    405     String8 error;
    406     ResXMLTree tree;
    407     tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
    408 
    409     size_t len;
    410     int depth = 0;
    411     ResXMLTree::event_code_t code;
    412     while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
    413         if (code == ResXMLTree::END_TAG) {
    414             depth--;
    415             const char16_t* ctag16 = tree.getElementName(&len);
    416             if (ctag16 == NULL) {
    417                 *outError = "failed to get XML element name (bad string pool)";
    418                 return Vector<String8>();
    419             }
    420             String8 tag(ctag16);
    421 
    422             if (depth == 0 && tag == serviceTagName) {
    423                 withinApduService = false;
    424             }
    425 
    426         } else if (code == ResXMLTree::START_TAG) {
    427             depth++;
    428             const char16_t* ctag16 = tree.getElementName(&len);
    429             if (ctag16 == NULL) {
    430                 *outError = "failed to get XML element name (bad string pool)";
    431                 return Vector<String8>();
    432             }
    433             String8 tag(ctag16);
    434 
    435             if (depth == 1) {
    436                 if (tag == serviceTagName) {
    437                     withinApduService = true;
    438                 }
    439             } else if (depth == 2 && withinApduService) {
    440                 if (tag == "aid-group") {
    441                     String8 category = AaptXml::getAttribute(tree, CATEGORY_ATTR, &error);
    442                     if (error != "") {
    443                         if (outError != NULL) *outError = error;
    444                         return Vector<String8>();
    445                     }
    446 
    447                     categories.add(category);
    448                 }
    449             }
    450         }
    451     }
    452     aidAsset->close();
    453     return categories;
    454 }
    455 
    456 static void printComponentPresence(const char* componentName) {
    457     printf("provides-component:'%s'\n", componentName);
    458 }
    459 
    460 /**
    461  * Represents a feature that has been automatically added due to
    462  * a pre-requisite or some other reason.
    463  */
    464 struct ImpliedFeature {
    465     /**
    466      * Name of the implied feature.
    467      */
    468     String8 name;
    469 
    470     /**
    471      * List of human-readable reasons for why this feature was implied.
    472      */
    473     SortedVector<String8> reasons;
    474 };
    475 
    476 /**
    477  * Represents a <feature-group> tag in the AndroidManifest.xml
    478  */
    479 struct FeatureGroup {
    480     FeatureGroup() : openGLESVersion(-1) {}
    481 
    482     /**
    483      * Human readable label
    484      */
    485     String8 label;
    486 
    487     /**
    488      * Explicit features defined in the group
    489      */
    490     KeyedVector<String8, bool> features;
    491 
    492     /**
    493      * OpenGL ES version required
    494      */
    495     int openGLESVersion;
    496 };
    497 
    498 static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
    499         const char* name, const char* reason) {
    500     String8 name8(name);
    501     ssize_t idx = impliedFeatures->indexOfKey(name8);
    502     if (idx < 0) {
    503         idx = impliedFeatures->add(name8, ImpliedFeature());
    504         impliedFeatures->editValueAt(idx).name = name8;
    505     }
    506     impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
    507 }
    508 
    509 static void printFeatureGroup(const FeatureGroup& grp,
    510         const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
    511     printf("feature-group: label='%s'\n", grp.label.string());
    512 
    513     if (grp.openGLESVersion > 0) {
    514         printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
    515     }
    516 
    517     const size_t numFeatures = grp.features.size();
    518     for (size_t i = 0; i < numFeatures; i++) {
    519         const bool required = grp.features[i];
    520 
    521         const String8& featureName = grp.features.keyAt(i);
    522         printf("  uses-feature%s: name='%s'\n", (required ? "" : "-not-required"),
    523                 ResTable::normalizeForOutput(featureName.string()).string());
    524     }
    525 
    526     const size_t numImpliedFeatures =
    527         (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
    528     for (size_t i = 0; i < numImpliedFeatures; i++) {
    529         const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
    530         if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
    531             // The feature is explicitly set, no need to use implied
    532             // definition.
    533             continue;
    534         }
    535 
    536         String8 printableFeatureName(ResTable::normalizeForOutput(
    537                     impliedFeature.name.string()));
    538         printf("  uses-feature: name='%s'\n", printableFeatureName.string());
    539         printf("  uses-implied-feature: name='%s' reason='",
    540                 printableFeatureName.string());
    541         const size_t numReasons = impliedFeature.reasons.size();
    542         for (size_t j = 0; j < numReasons; j++) {
    543             printf("%s", impliedFeature.reasons[j].string());
    544             if (j + 2 < numReasons) {
    545                 printf(", ");
    546             } else if (j + 1 < numReasons) {
    547                 printf(", and ");
    548             }
    549         }
    550         printf("'\n");
    551     }
    552 }
    553 
    554 static void addParentFeatures(FeatureGroup* grp, const String8& name) {
    555     if (name == "android.hardware.camera.autofocus" ||
    556             name == "android.hardware.camera.flash") {
    557         grp->features.add(String8("android.hardware.camera"), true);
    558     } else if (name == "android.hardware.location.gps" ||
    559             name == "android.hardware.location.network") {
    560         grp->features.add(String8("android.hardware.location"), true);
    561     } else if (name == "android.hardware.touchscreen.multitouch") {
    562         grp->features.add(String8("android.hardware.touchscreen"), true);
    563     } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
    564         grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
    565         grp->features.add(String8("android.hardware.touchscreen"), true);
    566     } else if (name == "android.hardware.opengles.aep") {
    567         const int openGLESVersion31 = 0x00030001;
    568         if (openGLESVersion31 > grp->openGLESVersion) {
    569             grp->openGLESVersion = openGLESVersion31;
    570         }
    571     }
    572 }
    573 
    574 /*
    575  * Handle the "dump" command, to extract select data from an archive.
    576  */
    577 extern char CONSOLE_DATA[2925]; // see EOF
    578 int doDump(Bundle* bundle)
    579 {
    580     status_t result = UNKNOWN_ERROR;
    581 
    582     if (bundle->getFileSpecCount() < 1) {
    583         fprintf(stderr, "ERROR: no dump option specified\n");
    584         return 1;
    585     }
    586 
    587     if (bundle->getFileSpecCount() < 2) {
    588         fprintf(stderr, "ERROR: no dump file specified\n");
    589         return 1;
    590     }
    591 
    592     const char* option = bundle->getFileSpecEntry(0);
    593     const char* filename = bundle->getFileSpecEntry(1);
    594 
    595     AssetManager assets;
    596     int32_t assetsCookie;
    597     if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
    598         fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
    599         return 1;
    600     }
    601 
    602     // Make a dummy config for retrieving resources...  we need to supply
    603     // non-default values for some configs so that we can retrieve resources
    604     // in the app that don't have a default.  The most important of these is
    605     // the API version because key resources like icons will have an implicit
    606     // version if they are using newer config types like density.
    607     ResTable_config config;
    608     memset(&config, 0, sizeof(ResTable_config));
    609     config.language[0] = 'e';
    610     config.language[1] = 'n';
    611     config.country[0] = 'U';
    612     config.country[1] = 'S';
    613     config.orientation = ResTable_config::ORIENTATION_PORT;
    614     config.density = ResTable_config::DENSITY_MEDIUM;
    615     config.sdkVersion = 10000; // Very high.
    616     config.screenWidthDp = 320;
    617     config.screenHeightDp = 480;
    618     config.smallestScreenWidthDp = 320;
    619     config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
    620     assets.setConfiguration(config);
    621 
    622     const ResTable& res = assets.getResources(false);
    623     if (&res == NULL) {
    624         fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
    625         return 1;
    626     } else if (res.getError() != NO_ERROR) {
    627         fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
    628         return 1;
    629     }
    630 
    631     // The dynamicRefTable can be null if there are no resources for this asset cookie.
    632     // This fine.
    633     const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
    634 
    635     Asset* asset = NULL;
    636 
    637     if (strcmp("resources", option) == 0) {
    638 #ifndef HAVE_ANDROID_OS
    639         res.print(bundle->getValues());
    640 #endif
    641 
    642     } else if (strcmp("strings", option) == 0) {
    643         const ResStringPool* pool = res.getTableStringBlock(0);
    644         printStringPool(pool);
    645 
    646     } else if (strcmp("xmltree", option) == 0) {
    647         if (bundle->getFileSpecCount() < 3) {
    648             fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
    649             goto bail;
    650         }
    651 
    652         for (int i=2; i<bundle->getFileSpecCount(); i++) {
    653             const char* resname = bundle->getFileSpecEntry(i);
    654             ResXMLTree tree(dynamicRefTable);
    655             asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
    656             if (asset == NULL) {
    657                 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
    658                 goto bail;
    659             }
    660 
    661             if (tree.setTo(asset->getBuffer(true),
    662                            asset->getLength()) != NO_ERROR) {
    663                 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
    664                 goto bail;
    665             }
    666             tree.restart();
    667             printXMLBlock(&tree);
    668             tree.uninit();
    669             delete asset;
    670             asset = NULL;
    671         }
    672 
    673     } else if (strcmp("xmlstrings", option) == 0) {
    674         if (bundle->getFileSpecCount() < 3) {
    675             fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
    676             goto bail;
    677         }
    678 
    679         for (int i=2; i<bundle->getFileSpecCount(); i++) {
    680             const char* resname = bundle->getFileSpecEntry(i);
    681             asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
    682             if (asset == NULL) {
    683                 fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
    684                 goto bail;
    685             }
    686 
    687             ResXMLTree tree(dynamicRefTable);
    688             if (tree.setTo(asset->getBuffer(true),
    689                            asset->getLength()) != NO_ERROR) {
    690                 fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
    691                 goto bail;
    692             }
    693             printStringPool(&tree.getStrings());
    694             delete asset;
    695             asset = NULL;
    696         }
    697 
    698     } else {
    699         asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
    700         if (asset == NULL) {
    701             fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
    702             goto bail;
    703         }
    704 
    705         ResXMLTree tree(dynamicRefTable);
    706         if (tree.setTo(asset->getBuffer(true),
    707                        asset->getLength()) != NO_ERROR) {
    708             fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
    709             goto bail;
    710         }
    711         tree.restart();
    712 
    713         if (strcmp("permissions", option) == 0) {
    714             size_t len;
    715             ResXMLTree::event_code_t code;
    716             int depth = 0;
    717             while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
    718                 if (code == ResXMLTree::END_TAG) {
    719                     depth--;
    720                     continue;
    721                 }
    722                 if (code != ResXMLTree::START_TAG) {
    723                     continue;
    724                 }
    725                 depth++;
    726                 const char16_t* ctag16 = tree.getElementName(&len);
    727                 if (ctag16 == NULL) {
    728                     fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
    729                     goto bail;
    730                 }
    731                 String8 tag(ctag16);
    732                 //printf("Depth %d tag %s\n", depth, tag.string());
    733                 if (depth == 1) {
    734                     if (tag != "manifest") {
    735                         fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
    736                         goto bail;
    737                     }
    738                     String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
    739                     printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
    740                 } else if (depth == 2 && tag == "permission") {
    741                     String8 error;
    742                     String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
    743                     if (error != "") {
    744                         fprintf(stderr, "ERROR: %s\n", error.string());
    745                         goto bail;
    746                     }
    747                     printf("permission: %s\n",
    748                             ResTable::normalizeForOutput(name.string()).string());
    749                 } else if (depth == 2 && tag == "uses-permission") {
    750                     String8 error;
    751                     String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
    752                     if (error != "") {
    753                         fprintf(stderr, "ERROR: %s\n", error.string());
    754                         goto bail;
    755                     }
    756                     printUsesPermission(name,
    757                             AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
    758                             AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
    759                 }
    760             }
    761         } else if (strcmp("badging", option) == 0) {
    762             Vector<String8> locales;
    763             res.getLocales(&locales);
    764 
    765             Vector<ResTable_config> configs;
    766             res.getConfigurations(&configs);
    767             SortedVector<int> densities;
    768             const size_t NC = configs.size();
    769             for (size_t i=0; i<NC; i++) {
    770                 int dens = configs[i].density;
    771                 if (dens == 0) {
    772                     dens = 160;
    773                 }
    774                 densities.add(dens);
    775             }
    776 
    777             size_t len;
    778             ResXMLTree::event_code_t code;
    779             int depth = 0;
    780             String8 error;
    781             bool withinActivity = false;
    782             bool isMainActivity = false;
    783             bool isLauncherActivity = false;
    784             bool isLeanbackLauncherActivity = false;
    785             bool isSearchable = false;
    786             bool withinApplication = false;
    787             bool withinSupportsInput = false;
    788             bool withinFeatureGroup = false;
    789             bool withinReceiver = false;
    790             bool withinService = false;
    791             bool withinProvider = false;
    792             bool withinIntentFilter = false;
    793             bool hasMainActivity = false;
    794             bool hasOtherActivities = false;
    795             bool hasOtherReceivers = false;
    796             bool hasOtherServices = false;
    797             bool hasIntentFilter = false;
    798 
    799             bool hasWallpaperService = false;
    800             bool hasImeService = false;
    801             bool hasAccessibilityService = false;
    802             bool hasPrintService = false;
    803             bool hasWidgetReceivers = false;
    804             bool hasDeviceAdminReceiver = false;
    805             bool hasPaymentService = false;
    806             bool hasDocumentsProvider = false;
    807             bool hasCameraActivity = false;
    808             bool hasCameraSecureActivity = false;
    809             bool hasLauncher = false;
    810             bool hasNotificationListenerService = false;
    811             bool hasDreamService = false;
    812 
    813             bool actMainActivity = false;
    814             bool actWidgetReceivers = false;
    815             bool actDeviceAdminEnabled = false;
    816             bool actImeService = false;
    817             bool actWallpaperService = false;
    818             bool actAccessibilityService = false;
    819             bool actPrintService = false;
    820             bool actHostApduService = false;
    821             bool actOffHostApduService = false;
    822             bool actDocumentsProvider = false;
    823             bool actNotificationListenerService = false;
    824             bool actDreamService = false;
    825             bool actCamera = false;
    826             bool actCameraSecure = false;
    827             bool catLauncher = false;
    828             bool hasMetaHostPaymentCategory = false;
    829             bool hasMetaOffHostPaymentCategory = false;
    830 
    831             // These permissions are required by services implementing services
    832             // the system binds to (IME, Accessibility, PrintServices, etc.)
    833             bool hasBindDeviceAdminPermission = false;
    834             bool hasBindInputMethodPermission = false;
    835             bool hasBindAccessibilityServicePermission = false;
    836             bool hasBindPrintServicePermission = false;
    837             bool hasBindNfcServicePermission = false;
    838             bool hasRequiredSafAttributes = false;
    839             bool hasBindNotificationListenerServicePermission = false;
    840             bool hasBindDreamServicePermission = false;
    841 
    842             // These two implement the implicit permissions that are granted
    843             // to pre-1.6 applications.
    844             bool hasWriteExternalStoragePermission = false;
    845             bool hasReadPhoneStatePermission = false;
    846 
    847             // If an app requests write storage, they will also get read storage.
    848             bool hasReadExternalStoragePermission = false;
    849 
    850             // Implement transition to read and write call log.
    851             bool hasReadContactsPermission = false;
    852             bool hasWriteContactsPermission = false;
    853             bool hasReadCallLogPermission = false;
    854             bool hasWriteCallLogPermission = false;
    855 
    856             // If an app declares itself as multiArch, we report the
    857             // native libraries differently.
    858             bool hasMultiArch = false;
    859 
    860             // This next group of variables is used to implement a group of
    861             // backward-compatibility heuristics necessitated by the addition of
    862             // some new uses-feature constants in 2.1 and 2.2. In most cases, the
    863             // heuristic is "if an app requests a permission but doesn't explicitly
    864             // request the corresponding <uses-feature>, presume it's there anyway".
    865 
    866             // 2.2 also added some other features that apps can request, but that
    867             // have no corresponding permission, so we cannot implement any
    868             // back-compatibility heuristic for them. The below are thus unnecessary
    869             // (but are retained here for documentary purposes.)
    870             //bool specCompassFeature = false;
    871             //bool specAccelerometerFeature = false;
    872             //bool specProximityFeature = false;
    873             //bool specAmbientLightFeature = false;
    874             //bool specLiveWallpaperFeature = false;
    875 
    876             int targetSdk = 0;
    877             int smallScreen = 1;
    878             int normalScreen = 1;
    879             int largeScreen = 1;
    880             int xlargeScreen = 1;
    881             int anyDensity = 1;
    882             int requiresSmallestWidthDp = 0;
    883             int compatibleWidthLimitDp = 0;
    884             int largestWidthLimitDp = 0;
    885             String8 pkg;
    886             String8 activityName;
    887             String8 activityLabel;
    888             String8 activityIcon;
    889             String8 activityBanner;
    890             String8 receiverName;
    891             String8 serviceName;
    892             Vector<String8> supportedInput;
    893 
    894             FeatureGroup commonFeatures;
    895             Vector<FeatureGroup> featureGroups;
    896             KeyedVector<String8, ImpliedFeature> impliedFeatures;
    897 
    898             while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
    899                 if (code == ResXMLTree::END_TAG) {
    900                     depth--;
    901                     if (depth < 2) {
    902                         if (withinSupportsInput && !supportedInput.isEmpty()) {
    903                             printf("supports-input: '");
    904                             const size_t N = supportedInput.size();
    905                             for (size_t i=0; i<N; i++) {
    906                                 printf("%s", ResTable::normalizeForOutput(
    907                                         supportedInput[i].string()).string());
    908                                 if (i != N - 1) {
    909                                     printf("' '");
    910                                 } else {
    911                                     printf("'\n");
    912                                 }
    913                             }
    914                             supportedInput.clear();
    915                         }
    916                         withinApplication = false;
    917                         withinSupportsInput = false;
    918                         withinFeatureGroup = false;
    919                     } else if (depth < 3) {
    920                         if (withinActivity && isMainActivity) {
    921                             String8 aName(getComponentName(pkg, activityName));
    922                             if (isLauncherActivity) {
    923                                 printf("launchable-activity:");
    924                                 if (aName.length() > 0) {
    925                                     printf(" name='%s' ",
    926                                             ResTable::normalizeForOutput(aName.string()).string());
    927                                 }
    928                                 printf(" label='%s' icon='%s'\n",
    929                                         ResTable::normalizeForOutput(activityLabel.string()).string(),
    930                                         ResTable::normalizeForOutput(activityIcon.string()).string());
    931                             }
    932                             if (isLeanbackLauncherActivity) {
    933                                 printf("leanback-launchable-activity:");
    934                                 if (aName.length() > 0) {
    935                                     printf(" name='%s' ",
    936                                             ResTable::normalizeForOutput(aName.string()).string());
    937                                 }
    938                                 printf(" label='%s' icon='%s' banner='%s'\n",
    939                                         ResTable::normalizeForOutput(activityLabel.string()).string(),
    940                                         ResTable::normalizeForOutput(activityIcon.string()).string(),
    941                                         ResTable::normalizeForOutput(activityBanner.string()).string());
    942                             }
    943                         }
    944                         if (!hasIntentFilter) {
    945                             hasOtherActivities |= withinActivity;
    946                             hasOtherReceivers |= withinReceiver;
    947                             hasOtherServices |= withinService;
    948                         } else {
    949                             if (withinService) {
    950                                 hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
    951                                         hasBindNfcServicePermission);
    952                                 hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
    953                                         hasBindNfcServicePermission);
    954                             }
    955                         }
    956                         withinActivity = false;
    957                         withinService = false;
    958                         withinReceiver = false;
    959                         withinProvider = false;
    960                         hasIntentFilter = false;
    961                         isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
    962                     } else if (depth < 4) {
    963                         if (withinIntentFilter) {
    964                             if (withinActivity) {
    965                                 hasMainActivity |= actMainActivity;
    966                                 hasLauncher |= catLauncher;
    967                                 hasCameraActivity |= actCamera;
    968                                 hasCameraSecureActivity |= actCameraSecure;
    969                                 hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
    970                             } else if (withinReceiver) {
    971                                 hasWidgetReceivers |= actWidgetReceivers;
    972                                 hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
    973                                         hasBindDeviceAdminPermission);
    974                                 hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
    975                             } else if (withinService) {
    976                                 hasImeService |= actImeService;
    977                                 hasWallpaperService |= actWallpaperService;
    978                                 hasAccessibilityService |= (actAccessibilityService &&
    979                                         hasBindAccessibilityServicePermission);
    980                                 hasPrintService |= (actPrintService && hasBindPrintServicePermission);
    981                                 hasNotificationListenerService |= actNotificationListenerService &&
    982                                         hasBindNotificationListenerServicePermission;
    983                                 hasDreamService |= actDreamService && hasBindDreamServicePermission;
    984                                 hasOtherServices |= (!actImeService && !actWallpaperService &&
    985                                         !actAccessibilityService && !actPrintService &&
    986                                         !actHostApduService && !actOffHostApduService &&
    987                                         !actNotificationListenerService);
    988                             } else if (withinProvider) {
    989                                 hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
    990                             }
    991                         }
    992                         withinIntentFilter = false;
    993                     }
    994                     continue;
    995                 }
    996                 if (code != ResXMLTree::START_TAG) {
    997                     continue;
    998                 }
    999                 depth++;
   1000 
   1001                 const char16_t* ctag16 = tree.getElementName(&len);
   1002                 if (ctag16 == NULL) {
   1003                     fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
   1004                     goto bail;
   1005                 }
   1006                 String8 tag(ctag16);
   1007                 //printf("Depth %d,  %s\n", depth, tag.string());
   1008                 if (depth == 1) {
   1009                     if (tag != "manifest") {
   1010                         fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
   1011                         goto bail;
   1012                     }
   1013                     pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
   1014                     printf("package: name='%s' ",
   1015                             ResTable::normalizeForOutput(pkg.string()).string());
   1016                     int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
   1017                             &error);
   1018                     if (error != "") {
   1019                         fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n",
   1020                                 error.string());
   1021                         goto bail;
   1022                     }
   1023                     if (versionCode > 0) {
   1024                         printf("versionCode='%d' ", versionCode);
   1025                     } else {
   1026                         printf("versionCode='' ");
   1027                     }
   1028                     String8 versionName = AaptXml::getResolvedAttribute(res, tree,
   1029                             VERSION_NAME_ATTR, &error);
   1030                     if (error != "") {
   1031                         fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n",
   1032                                 error.string());
   1033                         goto bail;
   1034                     }
   1035                     printf("versionName='%s'",
   1036                             ResTable::normalizeForOutput(versionName.string()).string());
   1037 
   1038                     String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
   1039                     if (!splitName.isEmpty()) {
   1040                         printf(" split='%s'", ResTable::normalizeForOutput(
   1041                                     splitName.string()).string());
   1042                     }
   1043 
   1044                     String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
   1045                             "platformBuildVersionName");
   1046                     printf(" platformBuildVersionName='%s'", platformVersionName.string());
   1047                     printf("\n");
   1048 
   1049                     int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
   1050                             INSTALL_LOCATION_ATTR, &error);
   1051                     if (error != "") {
   1052                         fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n",
   1053                                 error.string());
   1054                         goto bail;
   1055                     }
   1056 
   1057                     if (installLocation >= 0) {
   1058                         printf("install-location:'");
   1059                         switch (installLocation) {
   1060                             case 0:
   1061                                 printf("auto");
   1062                                 break;
   1063                             case 1:
   1064                                 printf("internalOnly");
   1065                                 break;
   1066                             case 2:
   1067                                 printf("preferExternal");
   1068                                 break;
   1069                             default:
   1070                                 fprintf(stderr, "Invalid installLocation %d\n", installLocation);
   1071                                 goto bail;
   1072                         }
   1073                         printf("'\n");
   1074                     }
   1075                 } else if (depth == 2) {
   1076                     withinApplication = false;
   1077                     if (tag == "application") {
   1078                         withinApplication = true;
   1079 
   1080                         String8 label;
   1081                         const size_t NL = locales.size();
   1082                         for (size_t i=0; i<NL; i++) {
   1083                             const char* localeStr =  locales[i].string();
   1084                             assets.setLocale(localeStr != NULL ? localeStr : "");
   1085                             String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
   1086                                     &error);
   1087                             if (llabel != "") {
   1088                                 if (localeStr == NULL || strlen(localeStr) == 0) {
   1089                                     label = llabel;
   1090                                     printf("application-label:'%s'\n",
   1091                                             ResTable::normalizeForOutput(llabel.string()).string());
   1092                                 } else {
   1093                                     if (label == "") {
   1094                                         label = llabel;
   1095                                     }
   1096                                     printf("application-label-%s:'%s'\n", localeStr,
   1097                                            ResTable::normalizeForOutput(llabel.string()).string());
   1098                                 }
   1099                             }
   1100                         }
   1101 
   1102                         ResTable_config tmpConfig = config;
   1103                         const size_t ND = densities.size();
   1104                         for (size_t i=0; i<ND; i++) {
   1105                             tmpConfig.density = densities[i];
   1106                             assets.setConfiguration(tmpConfig);
   1107                             String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
   1108                                     &error);
   1109                             if (icon != "") {
   1110                                 printf("application-icon-%d:'%s'\n", densities[i],
   1111                                         ResTable::normalizeForOutput(icon.string()).string());
   1112                             }
   1113                         }
   1114                         assets.setConfiguration(config);
   1115 
   1116                         String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
   1117                         if (error != "") {
   1118                             fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
   1119                                     error.string());
   1120                             goto bail;
   1121                         }
   1122                         int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
   1123                                 &error);
   1124                         if (error != "") {
   1125                             fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n",
   1126                                     error.string());
   1127                             goto bail;
   1128                         }
   1129 
   1130                         String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR, &error);
   1131                         if (error != "") {
   1132                             fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
   1133                                     error.string());
   1134                             goto bail;
   1135                         }
   1136                         printf("application: label='%s' ",
   1137                                 ResTable::normalizeForOutput(label.string()).string());
   1138                         printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
   1139                         if (banner != "") {
   1140                             printf(" banner='%s'", ResTable::normalizeForOutput(banner.string()).string());
   1141                         }
   1142                         printf("\n");
   1143                         if (testOnly != 0) {
   1144                             printf("testOnly='%d'\n", testOnly);
   1145                         }
   1146 
   1147                         int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree,
   1148                                 ISGAME_ATTR, 0, &error);
   1149                         if (error != "") {
   1150                             fprintf(stderr, "ERROR getting 'android:isGame' attribute: %s\n",
   1151                                     error.string());
   1152                             goto bail;
   1153                         }
   1154                         if (isGame != 0) {
   1155                             printf("application-isGame\n");
   1156                         }
   1157 
   1158                         int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree,
   1159                                 DEBUGGABLE_ATTR, 0, &error);
   1160                         if (error != "") {
   1161                             fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n",
   1162                                     error.string());
   1163                             goto bail;
   1164                         }
   1165                         if (debuggable != 0) {
   1166                             printf("application-debuggable\n");
   1167                         }
   1168 
   1169                         // We must search by name because the multiArch flag hasn't been API
   1170                         // frozen yet.
   1171                         int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
   1172                                 "multiArch");
   1173                         if (multiArchIndex >= 0) {
   1174                             Res_value value;
   1175                             if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
   1176                                 if (value.dataType >= Res_value::TYPE_FIRST_INT &&
   1177                                         value.dataType <= Res_value::TYPE_LAST_INT) {
   1178                                     hasMultiArch = value.data;
   1179                                 }
   1180                             }
   1181                         }
   1182                     } else if (tag == "uses-sdk") {
   1183                         int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
   1184                         if (error != "") {
   1185                             error = "";
   1186                             String8 name = AaptXml::getResolvedAttribute(res, tree,
   1187                                     MIN_SDK_VERSION_ATTR, &error);
   1188                             if (error != "") {
   1189                                 fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
   1190                                         error.string());
   1191                                 goto bail;
   1192                             }
   1193                             if (name == "Donut") targetSdk = 4;
   1194                             printf("sdkVersion:'%s'\n",
   1195                                     ResTable::normalizeForOutput(name.string()).string());
   1196                         } else if (code != -1) {
   1197                             targetSdk = code;
   1198                             printf("sdkVersion:'%d'\n", code);
   1199                         }
   1200                         code = AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR);
   1201                         if (code != -1) {
   1202                             printf("maxSdkVersion:'%d'\n", code);
   1203                         }
   1204                         code = AaptXml::getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
   1205                         if (error != "") {
   1206                             error = "";
   1207                             String8 name = AaptXml::getResolvedAttribute(res, tree,
   1208                                     TARGET_SDK_VERSION_ATTR, &error);
   1209                             if (error != "") {
   1210                                 fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
   1211                                         error.string());
   1212                                 goto bail;
   1213                             }
   1214                             if (name == "Donut" && targetSdk < 4) targetSdk = 4;
   1215                             printf("targetSdkVersion:'%s'\n",
   1216                                     ResTable::normalizeForOutput(name.string()).string());
   1217                         } else if (code != -1) {
   1218                             if (targetSdk < code) {
   1219                                 targetSdk = code;
   1220                             }
   1221                             printf("targetSdkVersion:'%d'\n", code);
   1222                         }
   1223                     } else if (tag == "uses-configuration") {
   1224                         int32_t reqTouchScreen = AaptXml::getIntegerAttribute(tree,
   1225                                 REQ_TOUCH_SCREEN_ATTR, 0);
   1226                         int32_t reqKeyboardType = AaptXml::getIntegerAttribute(tree,
   1227                                 REQ_KEYBOARD_TYPE_ATTR, 0);
   1228                         int32_t reqHardKeyboard = AaptXml::getIntegerAttribute(tree,
   1229                                 REQ_HARD_KEYBOARD_ATTR, 0);
   1230                         int32_t reqNavigation = AaptXml::getIntegerAttribute(tree,
   1231                                 REQ_NAVIGATION_ATTR, 0);
   1232                         int32_t reqFiveWayNav = AaptXml::getIntegerAttribute(tree,
   1233                                 REQ_FIVE_WAY_NAV_ATTR, 0);
   1234                         printf("uses-configuration:");
   1235                         if (reqTouchScreen != 0) {
   1236                             printf(" reqTouchScreen='%d'", reqTouchScreen);
   1237                         }
   1238                         if (reqKeyboardType != 0) {
   1239                             printf(" reqKeyboardType='%d'", reqKeyboardType);
   1240                         }
   1241                         if (reqHardKeyboard != 0) {
   1242                             printf(" reqHardKeyboard='%d'", reqHardKeyboard);
   1243                         }
   1244                         if (reqNavigation != 0) {
   1245                             printf(" reqNavigation='%d'", reqNavigation);
   1246                         }
   1247                         if (reqFiveWayNav != 0) {
   1248                             printf(" reqFiveWayNav='%d'", reqFiveWayNav);
   1249                         }
   1250                         printf("\n");
   1251                     } else if (tag == "supports-input") {
   1252                         withinSupportsInput = true;
   1253                     } else if (tag == "supports-screens") {
   1254                         smallScreen = AaptXml::getIntegerAttribute(tree,
   1255                                 SMALL_SCREEN_ATTR, 1);
   1256                         normalScreen = AaptXml::getIntegerAttribute(tree,
   1257                                 NORMAL_SCREEN_ATTR, 1);
   1258                         largeScreen = AaptXml::getIntegerAttribute(tree,
   1259                                 LARGE_SCREEN_ATTR, 1);
   1260                         xlargeScreen = AaptXml::getIntegerAttribute(tree,
   1261                                 XLARGE_SCREEN_ATTR, 1);
   1262                         anyDensity = AaptXml::getIntegerAttribute(tree,
   1263                                 ANY_DENSITY_ATTR, 1);
   1264                         requiresSmallestWidthDp = AaptXml::getIntegerAttribute(tree,
   1265                                 REQUIRES_SMALLEST_WIDTH_DP_ATTR, 0);
   1266                         compatibleWidthLimitDp = AaptXml::getIntegerAttribute(tree,
   1267                                 COMPATIBLE_WIDTH_LIMIT_DP_ATTR, 0);
   1268                         largestWidthLimitDp = AaptXml::getIntegerAttribute(tree,
   1269                                 LARGEST_WIDTH_LIMIT_DP_ATTR, 0);
   1270                     } else if (tag == "feature-group") {
   1271                         withinFeatureGroup = true;
   1272                         FeatureGroup group;
   1273                         group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
   1274                         if (error != "") {
   1275                             fprintf(stderr, "ERROR getting 'android:label' attribute:"
   1276                                     " %s\n", error.string());
   1277                             goto bail;
   1278                         }
   1279                         featureGroups.add(group);
   1280 
   1281                     } else if (tag == "uses-feature") {
   1282                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1283                         if (name != "" && error == "") {
   1284                             int req = AaptXml::getIntegerAttribute(tree,
   1285                                     REQUIRED_ATTR, 1);
   1286 
   1287                             commonFeatures.features.add(name, req);
   1288                             if (req) {
   1289                                 addParentFeatures(&commonFeatures, name);
   1290                             }
   1291                         } else {
   1292                             int vers = AaptXml::getIntegerAttribute(tree,
   1293                                     GL_ES_VERSION_ATTR, &error);
   1294                             if (error == "") {
   1295                                 if (vers > commonFeatures.openGLESVersion) {
   1296                                     commonFeatures.openGLESVersion = vers;
   1297                                 }
   1298                             }
   1299                         }
   1300                     } else if (tag == "uses-permission") {
   1301                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1302                         if (name != "" && error == "") {
   1303                             if (name == "android.permission.CAMERA") {
   1304                                 addImpliedFeature(&impliedFeatures, "android.hardware.camera",
   1305                                         String8::format("requested %s permission", name.string())
   1306                                         .string());
   1307                             } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
   1308                                 addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
   1309                                         String8::format("requested %s permission", name.string())
   1310                                         .string());
   1311                                 addImpliedFeature(&impliedFeatures, "android.hardware.location",
   1312                                         String8::format("requested %s permission", name.string())
   1313                                         .string());
   1314                             } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
   1315                                 addImpliedFeature(&impliedFeatures, "android.hardware.location",
   1316                                         String8::format("requested %s permission", name.string())
   1317                                         .string());
   1318                             } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
   1319                                 addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
   1320                                         String8::format("requested %s permission", name.string())
   1321                                         .string());
   1322                                 addImpliedFeature(&impliedFeatures, "android.hardware.location",
   1323                                         String8::format("requested %s permission", name.string())
   1324                                         .string());
   1325                             } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
   1326                                        name == "android.permission.INSTALL_LOCATION_PROVIDER") {
   1327                                 addImpliedFeature(&impliedFeatures, "android.hardware.location",
   1328                                         String8::format("requested %s permission", name.string())
   1329                                         .string());
   1330                             } else if (name == "android.permission.BLUETOOTH" ||
   1331                                        name == "android.permission.BLUETOOTH_ADMIN") {
   1332                                 if (targetSdk > 4) {
   1333                                     addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
   1334                                             String8::format("requested %s permission", name.string())
   1335                                             .string());
   1336                                     addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
   1337                                             "targetSdkVersion > 4");
   1338                                 }
   1339                             } else if (name == "android.permission.RECORD_AUDIO") {
   1340                                 addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
   1341                                         String8::format("requested %s permission", name.string())
   1342                                         .string());
   1343                             } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
   1344                                        name == "android.permission.CHANGE_WIFI_STATE" ||
   1345                                        name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
   1346                                 addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
   1347                                         String8::format("requested %s permission", name.string())
   1348                                         .string());
   1349                             } else if (name == "android.permission.CALL_PHONE" ||
   1350                                        name == "android.permission.CALL_PRIVILEGED" ||
   1351                                        name == "android.permission.MODIFY_PHONE_STATE" ||
   1352                                        name == "android.permission.PROCESS_OUTGOING_CALLS" ||
   1353                                        name == "android.permission.READ_SMS" ||
   1354                                        name == "android.permission.RECEIVE_SMS" ||
   1355                                        name == "android.permission.RECEIVE_MMS" ||
   1356                                        name == "android.permission.RECEIVE_WAP_PUSH" ||
   1357                                        name == "android.permission.SEND_SMS" ||
   1358                                        name == "android.permission.WRITE_APN_SETTINGS" ||
   1359                                        name == "android.permission.WRITE_SMS") {
   1360                                 addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
   1361                                         String8("requested a telephony permission").string());
   1362                             } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
   1363                                 hasWriteExternalStoragePermission = true;
   1364                             } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
   1365                                 hasReadExternalStoragePermission = true;
   1366                             } else if (name == "android.permission.READ_PHONE_STATE") {
   1367                                 hasReadPhoneStatePermission = true;
   1368                             } else if (name == "android.permission.READ_CONTACTS") {
   1369                                 hasReadContactsPermission = true;
   1370                             } else if (name == "android.permission.WRITE_CONTACTS") {
   1371                                 hasWriteContactsPermission = true;
   1372                             } else if (name == "android.permission.READ_CALL_LOG") {
   1373                                 hasReadCallLogPermission = true;
   1374                             } else if (name == "android.permission.WRITE_CALL_LOG") {
   1375                                 hasWriteCallLogPermission = true;
   1376                             }
   1377 
   1378                             printUsesPermission(name,
   1379                                     AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
   1380                                     AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
   1381                        } else {
   1382                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1383                                     error.string());
   1384                             goto bail;
   1385                         }
   1386                     } else if (tag == "uses-package") {
   1387                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1388                         if (name != "" && error == "") {
   1389                             printf("uses-package:'%s'\n",
   1390                                     ResTable::normalizeForOutput(name.string()).string());
   1391                         } else {
   1392                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1393                                     error.string());
   1394                                 goto bail;
   1395                         }
   1396                     } else if (tag == "original-package") {
   1397                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1398                         if (name != "" && error == "") {
   1399                             printf("original-package:'%s'\n",
   1400                                     ResTable::normalizeForOutput(name.string()).string());
   1401                         } else {
   1402                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1403                                     error.string());
   1404                                 goto bail;
   1405                         }
   1406                     } else if (tag == "supports-gl-texture") {
   1407                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1408                         if (name != "" && error == "") {
   1409                             printf("supports-gl-texture:'%s'\n",
   1410                                     ResTable::normalizeForOutput(name.string()).string());
   1411                         } else {
   1412                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1413                                     error.string());
   1414                                 goto bail;
   1415                         }
   1416                     } else if (tag == "compatible-screens") {
   1417                         printCompatibleScreens(tree, &error);
   1418                         if (error != "") {
   1419                             fprintf(stderr, "ERROR getting compatible screens: %s\n",
   1420                                     error.string());
   1421                             goto bail;
   1422                         }
   1423                         depth--;
   1424                     } else if (tag == "package-verifier") {
   1425                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1426                         if (name != "" && error == "") {
   1427                             String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR, &error);
   1428                             if (publicKey != "" && error == "") {
   1429                                 printf("package-verifier: name='%s' publicKey='%s'\n",
   1430                                         ResTable::normalizeForOutput(name.string()).string(),
   1431                                         ResTable::normalizeForOutput(publicKey.string()).string());
   1432                             }
   1433                         }
   1434                     }
   1435                 } else if (depth == 3) {
   1436                     withinActivity = false;
   1437                     withinReceiver = false;
   1438                     withinService = false;
   1439                     withinProvider = false;
   1440                     hasIntentFilter = false;
   1441                     hasMetaHostPaymentCategory = false;
   1442                     hasMetaOffHostPaymentCategory = false;
   1443                     hasBindDeviceAdminPermission = false;
   1444                     hasBindInputMethodPermission = false;
   1445                     hasBindAccessibilityServicePermission = false;
   1446                     hasBindPrintServicePermission = false;
   1447                     hasBindNfcServicePermission = false;
   1448                     hasRequiredSafAttributes = false;
   1449                     hasBindNotificationListenerServicePermission = false;
   1450                     hasBindDreamServicePermission = false;
   1451                     if (withinApplication) {
   1452                         if(tag == "activity") {
   1453                             withinActivity = true;
   1454                             activityName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1455                             if (error != "") {
   1456                                 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1457                                         error.string());
   1458                                 goto bail;
   1459                             }
   1460 
   1461                             activityLabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
   1462                                     &error);
   1463                             if (error != "") {
   1464                                 fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
   1465                                         error.string());
   1466                                 goto bail;
   1467                             }
   1468 
   1469                             activityIcon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR,
   1470                                     &error);
   1471                             if (error != "") {
   1472                                 fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
   1473                                         error.string());
   1474                                 goto bail;
   1475                             }
   1476 
   1477                             activityBanner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
   1478                                     &error);
   1479                             if (error != "") {
   1480                                 fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
   1481                                         error.string());
   1482                                 goto bail;
   1483                             }
   1484 
   1485                             int32_t orien = AaptXml::getResolvedIntegerAttribute(res, tree,
   1486                                     SCREEN_ORIENTATION_ATTR, &error);
   1487                             if (error == "") {
   1488                                 if (orien == 0 || orien == 6 || orien == 8) {
   1489                                     // Requests landscape, sensorLandscape, or reverseLandscape.
   1490                                     addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
   1491                                             "one or more activities have specified a landscape orientation");
   1492                                 } else if (orien == 1 || orien == 7 || orien == 9) {
   1493                                     // Requests portrait, sensorPortrait, or reversePortrait.
   1494                                     addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
   1495                                             "one or more activities have specified a portrait orientation");
   1496                                 }
   1497                             }
   1498                         } else if (tag == "uses-library") {
   1499                             String8 libraryName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1500                             if (error != "") {
   1501                                 fprintf(stderr,
   1502                                         "ERROR getting 'android:name' attribute for uses-library"
   1503                                         " %s\n", error.string());
   1504                                 goto bail;
   1505                             }
   1506                             int req = AaptXml::getIntegerAttribute(tree,
   1507                                     REQUIRED_ATTR, 1);
   1508                             printf("uses-library%s:'%s'\n",
   1509                                     req ? "" : "-not-required", ResTable::normalizeForOutput(
   1510                                             libraryName.string()).string());
   1511                         } else if (tag == "receiver") {
   1512                             withinReceiver = true;
   1513                             receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1514 
   1515                             if (error != "") {
   1516                                 fprintf(stderr,
   1517                                         "ERROR getting 'android:name' attribute for receiver:"
   1518                                         " %s\n", error.string());
   1519                                 goto bail;
   1520                             }
   1521 
   1522                             String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
   1523                                     &error);
   1524                             if (error == "") {
   1525                                 if (permission == "android.permission.BIND_DEVICE_ADMIN") {
   1526                                     hasBindDeviceAdminPermission = true;
   1527                                 }
   1528                             } else {
   1529                                 fprintf(stderr, "ERROR getting 'android:permission' attribute for"
   1530                                         " receiver '%s': %s\n", receiverName.string(), error.string());
   1531                             }
   1532                         } else if (tag == "service") {
   1533                             withinService = true;
   1534                             serviceName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1535 
   1536                             if (error != "") {
   1537                                 fprintf(stderr, "ERROR getting 'android:name' attribute for "
   1538                                         "service:%s\n", error.string());
   1539                                 goto bail;
   1540                             }
   1541 
   1542                             String8 permission = AaptXml::getAttribute(tree, PERMISSION_ATTR,
   1543                                     &error);
   1544                             if (error == "") {
   1545                                 if (permission == "android.permission.BIND_INPUT_METHOD") {
   1546                                     hasBindInputMethodPermission = true;
   1547                                 } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
   1548                                     hasBindAccessibilityServicePermission = true;
   1549                                 } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
   1550                                     hasBindPrintServicePermission = true;
   1551                                 } else if (permission == "android.permission.BIND_NFC_SERVICE") {
   1552                                     hasBindNfcServicePermission = true;
   1553                                 } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
   1554                                     hasBindNotificationListenerServicePermission = true;
   1555                                 } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
   1556                                     hasBindDreamServicePermission = true;
   1557                                 }
   1558                             } else {
   1559                                 fprintf(stderr, "ERROR getting 'android:permission' attribute for"
   1560                                         " service '%s': %s\n", serviceName.string(), error.string());
   1561                             }
   1562                         } else if (tag == "provider") {
   1563                             withinProvider = true;
   1564 
   1565                             bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
   1566                                     EXPORTED_ATTR, &error);
   1567                             if (error != "") {
   1568                                 fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
   1569                                         " %s\n", error.string());
   1570                                 goto bail;
   1571                             }
   1572 
   1573                             bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
   1574                                     res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
   1575                             if (error != "") {
   1576                                 fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
   1577                                         " %s\n", error.string());
   1578                                 goto bail;
   1579                             }
   1580 
   1581                             String8 permission = AaptXml::getResolvedAttribute(res, tree,
   1582                                     PERMISSION_ATTR, &error);
   1583                             if (error != "") {
   1584                                 fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
   1585                                         " %s\n", error.string());
   1586                                 goto bail;
   1587                             }
   1588 
   1589                             hasRequiredSafAttributes |= exported && grantUriPermissions &&
   1590                                 permission == "android.permission.MANAGE_DOCUMENTS";
   1591 
   1592                         } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
   1593                             String8 metaDataName = AaptXml::getResolvedAttribute(res, tree,
   1594                                     NAME_ATTR, &error);
   1595                             if (error != "") {
   1596                                 fprintf(stderr, "ERROR getting 'android:name' attribute for "
   1597                                         "meta-data:%s\n", error.string());
   1598                                 goto bail;
   1599                             }
   1600                             printf("meta-data: name='%s' ",
   1601                                     ResTable::normalizeForOutput(metaDataName.string()).string());
   1602                             printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
   1603                                     &error);
   1604                             if (error != "") {
   1605                                 // Try looking for a RESOURCE_ATTR
   1606                                 error = "";
   1607                                 printResolvedResourceAttribute(res, tree, RESOURCE_ATTR,
   1608                                         String8("resource"), &error);
   1609                                 if (error != "") {
   1610                                     fprintf(stderr, "ERROR getting 'android:value' or "
   1611                                             "'android:resource' attribute for "
   1612                                             "meta-data:%s\n", error.string());
   1613                                     goto bail;
   1614                                 }
   1615                             }
   1616                             printf("\n");
   1617                         } else if (withinSupportsInput && tag == "input-type") {
   1618                             String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1619                             if (name != "" && error == "") {
   1620                                 supportedInput.add(name);
   1621                             } else {
   1622                                 fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1623                                         error.string());
   1624                                 goto bail;
   1625                             }
   1626                         }
   1627                     } else if (withinFeatureGroup && tag == "uses-feature") {
   1628                         FeatureGroup& top = featureGroups.editTop();
   1629 
   1630                         String8 name = AaptXml::getResolvedAttribute(res, tree, NAME_ATTR, &error);
   1631                         if (name != "" && error == "") {
   1632                             top.features.add(name, true);
   1633                             addParentFeatures(&top, name);
   1634                         } else {
   1635                             int vers = AaptXml::getIntegerAttribute(tree, GL_ES_VERSION_ATTR,
   1636                                     &error);
   1637                             if (error == "") {
   1638                                 if (vers > top.openGLESVersion) {
   1639                                     top.openGLESVersion = vers;
   1640                                 }
   1641                             }
   1642                         }
   1643                     }
   1644                 } else if (depth == 4) {
   1645                     if (tag == "intent-filter") {
   1646                         hasIntentFilter = true;
   1647                         withinIntentFilter = true;
   1648                         actMainActivity = false;
   1649                         actWidgetReceivers = false;
   1650                         actImeService = false;
   1651                         actWallpaperService = false;
   1652                         actAccessibilityService = false;
   1653                         actPrintService = false;
   1654                         actDeviceAdminEnabled = false;
   1655                         actHostApduService = false;
   1656                         actOffHostApduService = false;
   1657                         actDocumentsProvider = false;
   1658                         actNotificationListenerService = false;
   1659                         actDreamService = false;
   1660                         actCamera = false;
   1661                         actCameraSecure = false;
   1662                         catLauncher = false;
   1663                     } else if (withinService && tag == "meta-data") {
   1664                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1665                         if (error != "") {
   1666                             fprintf(stderr, "ERROR getting 'android:name' attribute for"
   1667                                     " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
   1668                             goto bail;
   1669                         }
   1670 
   1671                         if (name == "android.nfc.cardemulation.host_apdu_service" ||
   1672                                 name == "android.nfc.cardemulation.off_host_apdu_service") {
   1673                             bool offHost = true;
   1674                             if (name == "android.nfc.cardemulation.host_apdu_service") {
   1675                                 offHost = false;
   1676                             }
   1677 
   1678                             String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
   1679                                     RESOURCE_ATTR, &error);
   1680                             if (error != "") {
   1681                                 fprintf(stderr, "ERROR getting 'android:resource' attribute for"
   1682                                         " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
   1683                                 goto bail;
   1684                             }
   1685 
   1686                             Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
   1687                                     offHost, &error);
   1688                             if (error != "") {
   1689                                 fprintf(stderr, "ERROR getting AID category for service '%s'\n",
   1690                                         serviceName.string());
   1691                                 goto bail;
   1692                             }
   1693 
   1694                             const size_t catLen = categories.size();
   1695                             for (size_t i = 0; i < catLen; i++) {
   1696                                 bool paymentCategory = (categories[i] == "payment");
   1697                                 if (offHost) {
   1698                                     hasMetaOffHostPaymentCategory |= paymentCategory;
   1699                                 } else {
   1700                                     hasMetaHostPaymentCategory |= paymentCategory;
   1701                                 }
   1702                             }
   1703                         }
   1704                     }
   1705                 } else if ((depth == 5) && withinIntentFilter) {
   1706                     String8 action;
   1707                     if (tag == "action") {
   1708                         action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1709                         if (error != "") {
   1710                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
   1711                                     error.string());
   1712                             goto bail;
   1713                         }
   1714 
   1715                         if (withinActivity) {
   1716                             if (action == "android.intent.action.MAIN") {
   1717                                 isMainActivity = true;
   1718                                 actMainActivity = true;
   1719                             } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
   1720                                     action == "android.media.action.VIDEO_CAMERA") {
   1721                                 actCamera = true;
   1722                             } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
   1723                                 actCameraSecure = true;
   1724                             }
   1725                         } else if (withinReceiver) {
   1726                             if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
   1727                                 actWidgetReceivers = true;
   1728                             } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
   1729                                 actDeviceAdminEnabled = true;
   1730                             }
   1731                         } else if (withinService) {
   1732                             if (action == "android.view.InputMethod") {
   1733                                 actImeService = true;
   1734                             } else if (action == "android.service.wallpaper.WallpaperService") {
   1735                                 actWallpaperService = true;
   1736                             } else if (action == "android.accessibilityservice.AccessibilityService") {
   1737                                 actAccessibilityService = true;
   1738                             } else if (action == "android.printservice.PrintService") {
   1739                                 actPrintService = true;
   1740                             } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
   1741                                 actHostApduService = true;
   1742                             } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
   1743                                 actOffHostApduService = true;
   1744                             } else if (action == "android.service.notification.NotificationListenerService") {
   1745                                 actNotificationListenerService = true;
   1746                             } else if (action == "android.service.dreams.DreamService") {
   1747                                 actDreamService = true;
   1748                             }
   1749                         } else if (withinProvider) {
   1750                             if (action == "android.content.action.DOCUMENTS_PROVIDER") {
   1751                                 actDocumentsProvider = true;
   1752                             }
   1753                         }
   1754                         if (action == "android.intent.action.SEARCH") {
   1755                             isSearchable = true;
   1756                         }
   1757                     }
   1758 
   1759                     if (tag == "category") {
   1760                         String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
   1761                         if (error != "") {
   1762                             fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
   1763                                     error.string());
   1764                             goto bail;
   1765                         }
   1766                         if (withinActivity) {
   1767                             if (category == "android.intent.category.LAUNCHER") {
   1768                                 isLauncherActivity = true;
   1769                             } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
   1770                                 isLeanbackLauncherActivity = true;
   1771                             } else if (category == "android.intent.category.HOME") {
   1772                                 catLauncher = true;
   1773                             }
   1774                         }
   1775                     }
   1776                 }
   1777             }
   1778 
   1779             // Pre-1.6 implicitly granted permission compatibility logic
   1780             if (targetSdk < 4) {
   1781                 if (!hasWriteExternalStoragePermission) {
   1782                     printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
   1783                     printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
   1784                             String8("targetSdkVersion < 4"));
   1785                     hasWriteExternalStoragePermission = true;
   1786                 }
   1787                 if (!hasReadPhoneStatePermission) {
   1788                     printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
   1789                     printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
   1790                             String8("targetSdkVersion < 4"));
   1791                 }
   1792             }
   1793 
   1794             // If the application has requested WRITE_EXTERNAL_STORAGE, we will
   1795             // force them to always take READ_EXTERNAL_STORAGE as well.  We always
   1796             // do this (regardless of target API version) because we can't have
   1797             // an app with write permission but not read permission.
   1798             if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
   1799                 printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
   1800                 printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
   1801                         String8("requested WRITE_EXTERNAL_STORAGE"));
   1802             }
   1803 
   1804             // Pre-JellyBean call log permission compatibility.
   1805             if (targetSdk < 16) {
   1806                 if (!hasReadCallLogPermission && hasReadContactsPermission) {
   1807                     printUsesPermission(String8("android.permission.READ_CALL_LOG"));
   1808                     printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
   1809                             String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
   1810                 }
   1811                 if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
   1812                     printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
   1813                     printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
   1814                             String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
   1815                 }
   1816             }
   1817 
   1818             addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
   1819                     "default feature for all apps");
   1820 
   1821             const size_t numFeatureGroups = featureGroups.size();
   1822             if (numFeatureGroups == 0) {
   1823                 // If no <feature-group> tags were defined, apply auto-implied features.
   1824                 printFeatureGroup(commonFeatures, &impliedFeatures);
   1825 
   1826             } else {
   1827                 // <feature-group> tags are defined, so we ignore implied features and
   1828                 for (size_t i = 0; i < numFeatureGroups; i++) {
   1829                     FeatureGroup& grp = featureGroups.editItemAt(i);
   1830 
   1831                     if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
   1832                         grp.openGLESVersion = commonFeatures.openGLESVersion;
   1833                     }
   1834 
   1835                     // Merge the features defined in the top level (not inside a <feature-group>)
   1836                     // with this feature group.
   1837                     const size_t numCommonFeatures = commonFeatures.features.size();
   1838                     for (size_t j = 0; j < numCommonFeatures; j++) {
   1839                         if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
   1840                             grp.features.add(commonFeatures.features.keyAt(j),
   1841                                     commonFeatures.features[j]);
   1842                         }
   1843                     }
   1844 
   1845                     if (!grp.features.isEmpty()) {
   1846                         printFeatureGroup(grp);
   1847                     }
   1848                 }
   1849             }
   1850 
   1851 
   1852             if (hasWidgetReceivers) {
   1853                 printComponentPresence("app-widget");
   1854             }
   1855             if (hasDeviceAdminReceiver) {
   1856                 printComponentPresence("device-admin");
   1857             }
   1858             if (hasImeService) {
   1859                 printComponentPresence("ime");
   1860             }
   1861             if (hasWallpaperService) {
   1862                 printComponentPresence("wallpaper");
   1863             }
   1864             if (hasAccessibilityService) {
   1865                 printComponentPresence("accessibility");
   1866             }
   1867             if (hasPrintService) {
   1868                 printComponentPresence("print-service");
   1869             }
   1870             if (hasPaymentService) {
   1871                 printComponentPresence("payment");
   1872             }
   1873             if (isSearchable) {
   1874                 printComponentPresence("search");
   1875             }
   1876             if (hasDocumentsProvider) {
   1877                 printComponentPresence("document-provider");
   1878             }
   1879             if (hasLauncher) {
   1880                 printComponentPresence("launcher");
   1881             }
   1882             if (hasNotificationListenerService) {
   1883                 printComponentPresence("notification-listener");
   1884             }
   1885             if (hasDreamService) {
   1886                 printComponentPresence("dream");
   1887             }
   1888             if (hasCameraActivity) {
   1889                 printComponentPresence("camera");
   1890             }
   1891             if (hasCameraSecureActivity) {
   1892                 printComponentPresence("camera-secure");
   1893             }
   1894 
   1895             if (hasMainActivity) {
   1896                 printf("main\n");
   1897             }
   1898             if (hasOtherActivities) {
   1899                 printf("other-activities\n");
   1900             }
   1901              if (hasOtherReceivers) {
   1902                 printf("other-receivers\n");
   1903             }
   1904             if (hasOtherServices) {
   1905                 printf("other-services\n");
   1906             }
   1907 
   1908             // For modern apps, if screen size buckets haven't been specified
   1909             // but the new width ranges have, then infer the buckets from them.
   1910             if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
   1911                     && requiresSmallestWidthDp > 0) {
   1912                 int compatWidth = compatibleWidthLimitDp;
   1913                 if (compatWidth <= 0) {
   1914                     compatWidth = requiresSmallestWidthDp;
   1915                 }
   1916                 if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
   1917                     smallScreen = -1;
   1918                 } else {
   1919                     smallScreen = 0;
   1920                 }
   1921                 if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
   1922                     normalScreen = -1;
   1923                 } else {
   1924                     normalScreen = 0;
   1925                 }
   1926                 if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
   1927                     largeScreen = -1;
   1928                 } else {
   1929                     largeScreen = 0;
   1930                 }
   1931                 if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
   1932                     xlargeScreen = -1;
   1933                 } else {
   1934                     xlargeScreen = 0;
   1935                 }
   1936             }
   1937 
   1938             // Determine default values for any unspecified screen sizes,
   1939             // based on the target SDK of the package.  As of 4 (donut)
   1940             // the screen size support was introduced, so all default to
   1941             // enabled.
   1942             if (smallScreen > 0) {
   1943                 smallScreen = targetSdk >= 4 ? -1 : 0;
   1944             }
   1945             if (normalScreen > 0) {
   1946                 normalScreen = -1;
   1947             }
   1948             if (largeScreen > 0) {
   1949                 largeScreen = targetSdk >= 4 ? -1 : 0;
   1950             }
   1951             if (xlargeScreen > 0) {
   1952                 // Introduced in Gingerbread.
   1953                 xlargeScreen = targetSdk >= 9 ? -1 : 0;
   1954             }
   1955             if (anyDensity > 0) {
   1956                 anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
   1957                         || compatibleWidthLimitDp > 0) ? -1 : 0;
   1958             }
   1959             printf("supports-screens:");
   1960             if (smallScreen != 0) {
   1961                 printf(" 'small'");
   1962             }
   1963             if (normalScreen != 0) {
   1964                 printf(" 'normal'");
   1965             }
   1966             if (largeScreen != 0) {
   1967                 printf(" 'large'");
   1968             }
   1969             if (xlargeScreen != 0) {
   1970                 printf(" 'xlarge'");
   1971             }
   1972             printf("\n");
   1973             printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
   1974             if (requiresSmallestWidthDp > 0) {
   1975                 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
   1976             }
   1977             if (compatibleWidthLimitDp > 0) {
   1978                 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
   1979             }
   1980             if (largestWidthLimitDp > 0) {
   1981                 printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
   1982             }
   1983 
   1984             printf("locales:");
   1985             const size_t NL = locales.size();
   1986             for (size_t i=0; i<NL; i++) {
   1987                 const char* localeStr =  locales[i].string();
   1988                 if (localeStr == NULL || strlen(localeStr) == 0) {
   1989                     localeStr = "--_--";
   1990                 }
   1991                 printf(" '%s'", localeStr);
   1992             }
   1993             printf("\n");
   1994 
   1995             printf("densities:");
   1996             const size_t ND = densities.size();
   1997             for (size_t i=0; i<ND; i++) {
   1998                 printf(" '%d'", densities[i]);
   1999             }
   2000             printf("\n");
   2001 
   2002             AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
   2003             if (dir != NULL) {
   2004                 if (dir->getFileCount() > 0) {
   2005                     SortedVector<String8> architectures;
   2006                     for (size_t i=0; i<dir->getFileCount(); i++) {
   2007                         architectures.add(ResTable::normalizeForOutput(
   2008                                 dir->getFileName(i).string()));
   2009                     }
   2010 
   2011                     bool outputAltNativeCode = false;
   2012                     // A multiArch package is one that contains 64-bit and
   2013                     // 32-bit versions of native code and expects 3rd-party
   2014                     // apps to load these native code libraries. Since most
   2015                     // 64-bit systems also support 32-bit apps, the apps
   2016                     // loading this multiArch package's code may be either
   2017                     // 32-bit or 64-bit.
   2018                     if (hasMultiArch) {
   2019                         // If this is a multiArch package, report the 64-bit
   2020                         // version only. Then as a separate entry, report the
   2021                         // rest.
   2022                         //
   2023                         // If we report the 32-bit architecture, this APK will
   2024                         // be installed on a 32-bit device, causing a large waste
   2025                         // of bandwidth and disk space. This assumes that
   2026                         // the developer of the multiArch package has also
   2027                         // made a version that is 32-bit only.
   2028                         String8 intel64("x86_64");
   2029                         String8 arm64("arm64-v8a");
   2030                         ssize_t index = architectures.indexOf(intel64);
   2031                         if (index < 0) {
   2032                             index = architectures.indexOf(arm64);
   2033                         }
   2034 
   2035                         if (index >= 0) {
   2036                             printf("native-code: '%s'\n", architectures[index].string());
   2037                             architectures.removeAt(index);
   2038                             outputAltNativeCode = true;
   2039                         }
   2040                     }
   2041 
   2042                     const size_t archCount = architectures.size();
   2043                     if (archCount > 0) {
   2044                         if (outputAltNativeCode) {
   2045                             printf("alt-");
   2046                         }
   2047                         printf("native-code:");
   2048                         for (size_t i = 0; i < archCount; i++) {
   2049                             printf(" '%s'", architectures[i].string());
   2050                         }
   2051                         printf("\n");
   2052                     }
   2053                 }
   2054                 delete dir;
   2055             }
   2056         } else if (strcmp("badger", option) == 0) {
   2057             printf("%s", CONSOLE_DATA);
   2058         } else if (strcmp("configurations", option) == 0) {
   2059             Vector<ResTable_config> configs;
   2060             res.getConfigurations(&configs);
   2061             const size_t N = configs.size();
   2062             for (size_t i=0; i<N; i++) {
   2063                 printf("%s\n", configs[i].toString().string());
   2064             }
   2065         } else {
   2066             fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
   2067             goto bail;
   2068         }
   2069     }
   2070 
   2071     result = NO_ERROR;
   2072 
   2073 bail:
   2074     if (asset) {
   2075         delete asset;
   2076     }
   2077     return (result != NO_ERROR);
   2078 }
   2079 
   2080 
   2081 /*
   2082  * Handle the "add" command, which wants to add files to a new or
   2083  * pre-existing archive.
   2084  */
   2085 int doAdd(Bundle* bundle)
   2086 {
   2087     ZipFile* zip = NULL;
   2088     status_t result = UNKNOWN_ERROR;
   2089     const char* zipFileName;
   2090 
   2091     if (bundle->getUpdate()) {
   2092         /* avoid confusion */
   2093         fprintf(stderr, "ERROR: can't use '-u' with add\n");
   2094         goto bail;
   2095     }
   2096 
   2097     if (bundle->getFileSpecCount() < 1) {
   2098         fprintf(stderr, "ERROR: must specify zip file name\n");
   2099         goto bail;
   2100     }
   2101     zipFileName = bundle->getFileSpecEntry(0);
   2102 
   2103     if (bundle->getFileSpecCount() < 2) {
   2104         fprintf(stderr, "NOTE: nothing to do\n");
   2105         goto bail;
   2106     }
   2107 
   2108     zip = openReadWrite(zipFileName, true);
   2109     if (zip == NULL) {
   2110         fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
   2111         goto bail;
   2112     }
   2113 
   2114     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
   2115         const char* fileName = bundle->getFileSpecEntry(i);
   2116 
   2117         if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
   2118             printf(" '%s'... (from gzip)\n", fileName);
   2119             result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
   2120         } else {
   2121             if (bundle->getJunkPath()) {
   2122                 String8 storageName = String8(fileName).getPathLeaf();
   2123                 printf(" '%s' as '%s'...\n", fileName,
   2124                         ResTable::normalizeForOutput(storageName.string()).string());
   2125                 result = zip->add(fileName, storageName.string(),
   2126                                   bundle->getCompressionMethod(), NULL);
   2127             } else {
   2128                 printf(" '%s'...\n", fileName);
   2129                 result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
   2130             }
   2131         }
   2132         if (result != NO_ERROR) {
   2133             fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
   2134             if (result == NAME_NOT_FOUND) {
   2135                 fprintf(stderr, ": file not found\n");
   2136             } else if (result == ALREADY_EXISTS) {
   2137                 fprintf(stderr, ": already exists in archive\n");
   2138             } else {
   2139                 fprintf(stderr, "\n");
   2140             }
   2141             goto bail;
   2142         }
   2143     }
   2144 
   2145     result = NO_ERROR;
   2146 
   2147 bail:
   2148     delete zip;
   2149     return (result != NO_ERROR);
   2150 }
   2151 
   2152 
   2153 /*
   2154  * Delete files from an existing archive.
   2155  */
   2156 int doRemove(Bundle* bundle)
   2157 {
   2158     ZipFile* zip = NULL;
   2159     status_t result = UNKNOWN_ERROR;
   2160     const char* zipFileName;
   2161 
   2162     if (bundle->getFileSpecCount() < 1) {
   2163         fprintf(stderr, "ERROR: must specify zip file name\n");
   2164         goto bail;
   2165     }
   2166     zipFileName = bundle->getFileSpecEntry(0);
   2167 
   2168     if (bundle->getFileSpecCount() < 2) {
   2169         fprintf(stderr, "NOTE: nothing to do\n");
   2170         goto bail;
   2171     }
   2172 
   2173     zip = openReadWrite(zipFileName, false);
   2174     if (zip == NULL) {
   2175         fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
   2176             zipFileName);
   2177         goto bail;
   2178     }
   2179 
   2180     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
   2181         const char* fileName = bundle->getFileSpecEntry(i);
   2182         ZipEntry* entry;
   2183 
   2184         entry = zip->getEntryByName(fileName);
   2185         if (entry == NULL) {
   2186             printf(" '%s' NOT FOUND\n", fileName);
   2187             continue;
   2188         }
   2189 
   2190         result = zip->remove(entry);
   2191 
   2192         if (result != NO_ERROR) {
   2193             fprintf(stderr, "Unable to delete '%s' from '%s'\n",
   2194                 bundle->getFileSpecEntry(i), zipFileName);
   2195             goto bail;
   2196         }
   2197     }
   2198 
   2199     /* update the archive */
   2200     zip->flush();
   2201 
   2202 bail:
   2203     delete zip;
   2204     return (result != NO_ERROR);
   2205 }
   2206 
   2207 static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
   2208     const size_t numDirs = dir->getDirs().size();
   2209     for (size_t i = 0; i < numDirs; i++) {
   2210         bool ignore = ignoreConfig;
   2211         const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
   2212         const char* dirStr = subDir->getLeaf().string();
   2213         if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
   2214             ignore = true;
   2215         }
   2216         status_t err = addResourcesToBuilder(subDir, builder, ignore);
   2217         if (err != NO_ERROR) {
   2218             return err;
   2219         }
   2220     }
   2221 
   2222     const size_t numFiles = dir->getFiles().size();
   2223     for (size_t i = 0; i < numFiles; i++) {
   2224         sp<AaptGroup> gp = dir->getFiles().valueAt(i);
   2225         const size_t numConfigs = gp->getFiles().size();
   2226         for (size_t j = 0; j < numConfigs; j++) {
   2227             status_t err = NO_ERROR;
   2228             if (ignoreConfig) {
   2229                 err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
   2230             } else {
   2231                 err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
   2232             }
   2233             if (err != NO_ERROR) {
   2234                 fprintf(stderr, "Failed to add %s (%s) to builder.\n",
   2235                         gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
   2236                 return err;
   2237             }
   2238         }
   2239     }
   2240     return NO_ERROR;
   2241 }
   2242 
   2243 static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
   2244     if (split->isBase()) {
   2245         return original;
   2246     }
   2247 
   2248     String8 ext(original.getPathExtension());
   2249     if (ext == String8(".apk")) {
   2250         return String8::format("%s_%s%s",
   2251                 original.getBasePath().string(),
   2252                 split->getDirectorySafeName().string(),
   2253                 ext.string());
   2254     }
   2255 
   2256     return String8::format("%s_%s", original.string(),
   2257             split->getDirectorySafeName().string());
   2258 }
   2259 
   2260 /*
   2261  * Package up an asset directory and associated application files.
   2262  */
   2263 int doPackage(Bundle* bundle)
   2264 {
   2265     const char* outputAPKFile;
   2266     int retVal = 1;
   2267     status_t err;
   2268     sp<AaptAssets> assets;
   2269     int N;
   2270     FILE* fp;
   2271     String8 dependencyFile;
   2272     sp<ApkBuilder> builder;
   2273 
   2274     // -c en_XA or/and ar_XB means do pseudolocalization
   2275     sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
   2276     err = configFilter->parse(bundle->getConfigurations());
   2277     if (err != NO_ERROR) {
   2278         goto bail;
   2279     }
   2280     if (configFilter->containsPseudo()) {
   2281         bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
   2282     }
   2283     if (configFilter->containsPseudoBidi()) {
   2284         bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
   2285     }
   2286 
   2287     N = bundle->getFileSpecCount();
   2288     if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
   2289             && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
   2290         fprintf(stderr, "ERROR: no input files\n");
   2291         goto bail;
   2292     }
   2293 
   2294     outputAPKFile = bundle->getOutputAPKFile();
   2295 
   2296     // Make sure the filenames provided exist and are of the appropriate type.
   2297     if (outputAPKFile) {
   2298         FileType type;
   2299         type = getFileType(outputAPKFile);
   2300         if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
   2301             fprintf(stderr,
   2302                 "ERROR: output file '%s' exists but is not regular file\n",
   2303                 outputAPKFile);
   2304             goto bail;
   2305         }
   2306     }
   2307 
   2308     // Load the assets.
   2309     assets = new AaptAssets();
   2310 
   2311     // Set up the resource gathering in assets if we're going to generate
   2312     // dependency files. Every time we encounter a resource while slurping
   2313     // the tree, we'll add it to these stores so we have full resource paths
   2314     // to write to a dependency file.
   2315     if (bundle->getGenDependencies()) {
   2316         sp<FilePathStore> resPathStore = new FilePathStore;
   2317         assets->setFullResPaths(resPathStore);
   2318         sp<FilePathStore> assetPathStore = new FilePathStore;
   2319         assets->setFullAssetPaths(assetPathStore);
   2320     }
   2321 
   2322     err = assets->slurpFromArgs(bundle);
   2323     if (err < 0) {
   2324         goto bail;
   2325     }
   2326 
   2327     if (bundle->getVerbose()) {
   2328         assets->print(String8());
   2329     }
   2330 
   2331     // Create the ApkBuilder, which will collect the compiled files
   2332     // to write to the final APK (or sets of APKs if we are building
   2333     // a Split APK.
   2334     builder = new ApkBuilder(configFilter);
   2335 
   2336     // If we are generating a Split APK, find out which configurations to split on.
   2337     if (bundle->getSplitConfigurations().size() > 0) {
   2338         const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
   2339         const size_t numSplits = splitStrs.size();
   2340         for (size_t i = 0; i < numSplits; i++) {
   2341             std::set<ConfigDescription> configs;
   2342             if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
   2343                 fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
   2344                 goto bail;
   2345             }
   2346 
   2347             err = builder->createSplitForConfigs(configs);
   2348             if (err != NO_ERROR) {
   2349                 goto bail;
   2350             }
   2351         }
   2352     }
   2353 
   2354     // If they asked for any fileAs that need to be compiled, do so.
   2355     if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
   2356         err = buildResources(bundle, assets, builder);
   2357         if (err != 0) {
   2358             goto bail;
   2359         }
   2360     }
   2361 
   2362     // At this point we've read everything and processed everything.  From here
   2363     // on out it's just writing output files.
   2364     if (SourcePos::hasErrors()) {
   2365         goto bail;
   2366     }
   2367 
   2368     // Update symbols with information about which ones are needed as Java symbols.
   2369     assets->applyJavaSymbols();
   2370     if (SourcePos::hasErrors()) {
   2371         goto bail;
   2372     }
   2373 
   2374     // If we've been asked to generate a dependency file, do that here
   2375     if (bundle->getGenDependencies()) {
   2376         // If this is the packaging step, generate the dependency file next to
   2377         // the output apk (e.g. bin/resources.ap_.d)
   2378         if (outputAPKFile) {
   2379             dependencyFile = String8(outputAPKFile);
   2380             // Add the .d extension to the dependency file.
   2381             dependencyFile.append(".d");
   2382         } else {
   2383             // Else if this is the R.java dependency generation step,
   2384             // generate the dependency file in the R.java package subdirectory
   2385             // e.g. gen/com/foo/app/R.java.d
   2386             dependencyFile = String8(bundle->getRClassDir());
   2387             dependencyFile.appendPath("R.java.d");
   2388         }
   2389         // Make sure we have a clean dependency file to start with
   2390         fp = fopen(dependencyFile, "w");
   2391         fclose(fp);
   2392     }
   2393 
   2394     // Write out R.java constants
   2395     if (!assets->havePrivateSymbols()) {
   2396         if (bundle->getCustomPackage() == NULL) {
   2397             // Write the R.java file into the appropriate class directory
   2398             // e.g. gen/com/foo/app/R.java
   2399             err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
   2400                     bundle->getBuildSharedLibrary());
   2401         } else {
   2402             const String8 customPkg(bundle->getCustomPackage());
   2403             err = writeResourceSymbols(bundle, assets, customPkg, true,
   2404                     bundle->getBuildSharedLibrary());
   2405         }
   2406         if (err < 0) {
   2407             goto bail;
   2408         }
   2409         // If we have library files, we're going to write our R.java file into
   2410         // the appropriate class directory for those libraries as well.
   2411         // e.g. gen/com/foo/app/lib/R.java
   2412         if (bundle->getExtraPackages() != NULL) {
   2413             // Split on colon
   2414             String8 libs(bundle->getExtraPackages());
   2415             char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
   2416             while (packageString != NULL) {
   2417                 // Write the R.java file out with the correct package name
   2418                 err = writeResourceSymbols(bundle, assets, String8(packageString), true,
   2419                         bundle->getBuildSharedLibrary());
   2420                 if (err < 0) {
   2421                     goto bail;
   2422                 }
   2423                 packageString = strtok(NULL, ":");
   2424             }
   2425             libs.unlockBuffer();
   2426         }
   2427     } else {
   2428         err = writeResourceSymbols(bundle, assets, assets->getPackage(), false, false);
   2429         if (err < 0) {
   2430             goto bail;
   2431         }
   2432         err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true, false);
   2433         if (err < 0) {
   2434             goto bail;
   2435         }
   2436     }
   2437 
   2438     // Write out the ProGuard file
   2439     err = writeProguardFile(bundle, assets);
   2440     if (err < 0) {
   2441         goto bail;
   2442     }
   2443 
   2444     // Write the apk
   2445     if (outputAPKFile) {
   2446         // Gather all resources and add them to the APK Builder. The builder will then
   2447         // figure out which Split they belong in.
   2448         err = addResourcesToBuilder(assets, builder);
   2449         if (err != NO_ERROR) {
   2450             goto bail;
   2451         }
   2452 
   2453         const Vector<sp<ApkSplit> >& splits = builder->getSplits();
   2454         const size_t numSplits = splits.size();
   2455         for (size_t i = 0; i < numSplits; i++) {
   2456             const sp<ApkSplit>& split = splits[i];
   2457             String8 outputPath = buildApkName(String8(outputAPKFile), split);
   2458             err = writeAPK(bundle, outputPath, split);
   2459             if (err != NO_ERROR) {
   2460                 fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
   2461                 goto bail;
   2462             }
   2463         }
   2464     }
   2465 
   2466     // If we've been asked to generate a dependency file, we need to finish up here.
   2467     // the writeResourceSymbols and writeAPK functions have already written the target
   2468     // half of the dependency file, now we need to write the prerequisites. (files that
   2469     // the R.java file or .ap_ file depend on)
   2470     if (bundle->getGenDependencies()) {
   2471         // Now that writeResourceSymbols or writeAPK has taken care of writing
   2472         // the targets to our dependency file, we'll write the prereqs
   2473         fp = fopen(dependencyFile, "a+");
   2474         fprintf(fp, " : ");
   2475         bool includeRaw = (outputAPKFile != NULL);
   2476         err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
   2477         // Also manually add the AndroidManifeset since it's not under res/ or assets/
   2478         // and therefore was not added to our pathstores during slurping
   2479         fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
   2480         fclose(fp);
   2481     }
   2482 
   2483     retVal = 0;
   2484 bail:
   2485     if (SourcePos::hasErrors()) {
   2486         SourcePos::printErrors(stderr);
   2487     }
   2488     return retVal;
   2489 }
   2490 
   2491 /*
   2492  * Do PNG Crunching
   2493  * PRECONDITIONS
   2494  *  -S flag points to a source directory containing drawable* folders
   2495  *  -C flag points to destination directory. The folder structure in the
   2496  *     source directory will be mirrored to the destination (cache) directory
   2497  *
   2498  * POSTCONDITIONS
   2499  *  Destination directory will be updated to match the PNG files in
   2500  *  the source directory.
   2501  */
   2502 int doCrunch(Bundle* bundle)
   2503 {
   2504     fprintf(stdout, "Crunching PNG Files in ");
   2505     fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
   2506     fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
   2507 
   2508     updatePreProcessedCache(bundle);
   2509 
   2510     return NO_ERROR;
   2511 }
   2512 
   2513 /*
   2514  * Do PNG Crunching on a single flag
   2515  *  -i points to a single png file
   2516  *  -o points to a single png output file
   2517  */
   2518 int doSingleCrunch(Bundle* bundle)
   2519 {
   2520     fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
   2521     fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
   2522 
   2523     String8 input(bundle->getSingleCrunchInputFile());
   2524     String8 output(bundle->getSingleCrunchOutputFile());
   2525 
   2526     if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
   2527         // we can't return the status_t as it gets truncate to the lower 8 bits.
   2528         return 42;
   2529     }
   2530 
   2531     return NO_ERROR;
   2532 }
   2533 
   2534 int runInDaemonMode(Bundle* bundle) {
   2535     std::cout << "Ready" << std::endl;
   2536     for (std::string cmd; std::getline(std::cin, cmd);) {
   2537         if (cmd == "quit") {
   2538             return NO_ERROR;
   2539         } else if (cmd == "s") {
   2540             // Two argument crunch
   2541             std::string inputFile, outputFile;
   2542             std::getline(std::cin, inputFile);
   2543             std::getline(std::cin, outputFile);
   2544             bundle->setSingleCrunchInputFile(inputFile.c_str());
   2545             bundle->setSingleCrunchOutputFile(outputFile.c_str());
   2546             std::cout << "Crunching " << inputFile << std::endl;
   2547             if (doSingleCrunch(bundle) != NO_ERROR) {
   2548                 std::cout << "Error" << std::endl;
   2549             }
   2550             std::cout << "Done" << std::endl;
   2551         } else {
   2552             // in case of invalid command, just bail out.
   2553             std::cerr << "Unknown command" << std::endl;
   2554             return -1;
   2555         }
   2556     }
   2557     return -1;
   2558 }
   2559 
   2560 char CONSOLE_DATA[2925] = {
   2561     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2562     32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2563     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2564     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
   2565     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
   2566     86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
   2567     62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2568     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2569     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
   2570     81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
   2571     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
   2572     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2573     32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
   2574     59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2575     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2576     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
   2577     59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
   2578     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2579     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2580     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
   2581     58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
   2582     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
   2583     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
   2584     47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
   2585     121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2586     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2587     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
   2588     81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
   2589     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
   2590     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2591     32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
   2592     59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2593     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2594     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
   2595     59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
   2596     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2597     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2598     32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
   2599     70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
   2600     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
   2601     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2602     32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
   2603     81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2604     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2605     32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
   2606     81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
   2607     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
   2608     32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
   2609     59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
   2610     60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2611     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
   2612     61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
   2613     61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
   2614     46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2615     32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
   2616     59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
   2617     109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
   2618     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
   2619     67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
   2620     59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
   2621     61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
   2622     32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
   2623     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
   2624     73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
   2625     59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
   2626     32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
   2627     59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
   2628     46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
   2629     97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
   2630     46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
   2631     119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
   2632     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
   2633     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2634     32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
   2635     119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
   2636     59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
   2637     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2638     32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
   2639     81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
   2640     87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
   2641     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
   2642     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
   2643     45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
   2644     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2645     32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
   2646     81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
   2647     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
   2648     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
   2649     59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
   2650     59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2651     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2652     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
   2653     81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
   2654     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2655     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2656     32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
   2657     81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2658     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
   2659     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
   2660     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
   2661     32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2662     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2663     32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
   2664     81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
   2665     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
   2666     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2667     58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
   2668     61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2669     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2670     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
   2671     81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
   2672     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2673     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2674     32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
   2675     81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2676     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
   2677     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
   2678     59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
   2679     59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2680     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2681     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
   2682     58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
   2683     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
   2684     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
   2685     61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
   2686     59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
   2687     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
   2688     32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
   2689     32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
   2690     61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2691     32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2692     32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
   2693     59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
   2694     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
   2695     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
   2696     59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
   2697     59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2698     32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2699     32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
   2700     32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
   2701     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
   2702     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2703     46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
   2704     46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2705     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
   2706     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
   2707     59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
   2708     59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2709     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2710     32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
   2711     32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
   2712     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
   2713     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
   2714     59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
   2715     59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2716     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2717     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
   2718     32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
   2719     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2720     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2721     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2722     32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
   2723     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
   2724   };
   2725