OSDN Git Service

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