OSDN Git Service

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