OSDN Git Service

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