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