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