2 // Copyright 2006 The Android Open Source Project 
   4 // Android Asset Packaging Tool main entry point. 
   8 #include "ResourceFilter.h" 
   9 #include "ResourceTable.h" 
  12 #include <utils/Log.h> 
  13 #include <utils/threads.h> 
  14 #include <utils/List.h> 
  15 #include <utils/Errors.h> 
  20 using namespace android
; 
  23  * Show version info.  All the cool kids do it. 
  25 int doVersion(Bundle
* bundle
) 
  27     if (bundle
->getFileSpecCount() != 0) 
  28         printf("(ignoring extra arguments)\n"); 
  29     printf("Android Asset Packaging Tool, v0.2\n"); 
  36  * Open the file read only.  The call fails if the file doesn't exist. 
  38  * Returns NULL on failure. 
  40 ZipFile
* openReadOnly(const char* fileName
) 
  46     result 
= zip
->open(fileName
, ZipFile::kOpenReadOnly
); 
  47     if (result 
!= NO_ERROR
) { 
  48         if (result 
== NAME_NOT_FOUND
) 
  49             fprintf(stderr
, "ERROR: '%s' not found\n", fileName
); 
  50         else if (result 
== PERMISSION_DENIED
) 
  51             fprintf(stderr
, "ERROR: '%s' access denied\n", fileName
); 
  53             fprintf(stderr
, "ERROR: failed opening '%s' as Zip file\n", 
  63  * Open the file read-write.  The file will be created if it doesn't 
  64  * already exist and "okayToCreate" is set. 
  66  * Returns NULL on failure. 
  68 ZipFile
* openReadWrite(const char* fileName
, bool okayToCreate
) 
  74     flags 
= ZipFile::kOpenReadWrite
; 
  76         flags 
|= ZipFile::kOpenCreate
; 
  79     result 
= zip
->open(fileName
, flags
); 
  80     if (result 
!= NO_ERROR
) { 
  92  * Return a short string describing the compression method. 
  94 const char* compressionName(int method
) 
  96     if (method 
== ZipEntry::kCompressStored
) 
  98     else if (method 
== ZipEntry::kCompressDeflated
) 
 105  * Return the percent reduction in size (0% == no compression). 
 107 int calcPercent(long uncompressedLen
, long compressedLen
) 
 109     if (!uncompressedLen
) 
 112         return (int) (100.0 - (compressedLen 
* 100.0) / uncompressedLen 
+ 0.5); 
 116  * Handle the "list" command, which can be a simple file dump or 
 119  * The verbose listing closely matches the output of the Info-ZIP "unzip" 
 122 int doList(Bundle
* bundle
) 
 126     const ZipEntry
* entry
; 
 127     long totalUncLen
, totalCompLen
; 
 128     const char* zipFileName
; 
 130     if (bundle
->getFileSpecCount() != 1) { 
 131         fprintf(stderr
, "ERROR: specify zip file name (only)\n"); 
 134     zipFileName 
= bundle
->getFileSpecEntry(0); 
 136     zip 
= openReadOnly(zipFileName
); 
 142     if (bundle
->getVerbose()) { 
 143         printf("Archive:  %s\n", zipFileName
); 
 145             " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n"); 
 147             "--------  ------  ------- -----  -------      ----  ----  ------    ----\n"); 
 150     totalUncLen 
= totalCompLen 
= 0; 
 152     count 
= zip
->getNumEntries(); 
 153     for (i 
= 0; i 
< count
; i
++) { 
 154         entry 
= zip
->getEntryByIndex(i
); 
 155         if (bundle
->getVerbose()) { 
 159             when 
= entry
->getModWhen(); 
 160             strftime(dateBuf
, sizeof(dateBuf
), "%m-%d-%y %H:%M", 
 163             printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n", 
 164                 (long) entry
->getUncompressedLen(), 
 165                 compressionName(entry
->getCompressionMethod()), 
 166                 (long) entry
->getCompressedLen(), 
 167                 calcPercent(entry
->getUncompressedLen(), 
 168                             entry
->getCompressedLen()), 
 169                 (size_t) entry
->getLFHOffset(), 
 172                 entry
->getFileName()); 
 174             printf("%s\n", entry
->getFileName()); 
 177         totalUncLen 
+= entry
->getUncompressedLen(); 
 178         totalCompLen 
+= entry
->getCompressedLen(); 
 181     if (bundle
->getVerbose()) { 
 183         "--------          -------  ---                            -------\n"); 
 184         printf("%8ld          %7ld  %2d%%                            %d files\n", 
 187             calcPercent(totalUncLen
, totalCompLen
), 
 188             zip
->getNumEntries()); 
 191     if (bundle
->getAndroidList()) { 
 193         if (!assets
.addAssetPath(String8(zipFileName
), NULL
)) { 
 194             fprintf(stderr
, "ERROR: list -a failed because assets could not be loaded\n"); 
 198         const ResTable
& res 
= assets
.getResources(false); 
 200             printf("\nNo resource table found.\n"); 
 202 #ifndef HAVE_ANDROID_OS 
 203             printf("\nResource table:\n"); 
 208         Asset
* manifestAsset 
= assets
.openNonAsset("AndroidManifest.xml", 
 209                                                    Asset::ACCESS_BUFFER
); 
 210         if (manifestAsset 
== NULL
) { 
 211             printf("\nNo AndroidManifest.xml found.\n"); 
 213             printf("\nAndroid manifest:\n"); 
 215             tree
.setTo(manifestAsset
->getBuffer(true), 
 216                        manifestAsset
->getLength()); 
 217             printXMLBlock(&tree
); 
 219         delete manifestAsset
; 
 229 static ssize_t 
indexOfAttribute(const ResXMLTree
& tree
, uint32_t attrRes
) 
 231     size_t N 
= tree
.getAttributeCount(); 
 232     for (size_t i
=0; i
<N
; i
++) { 
 233         if (tree
.getAttributeNameResID(i
) == attrRes
) { 
 240 String8 
getAttribute(const ResXMLTree
& tree
, const char* ns
, 
 241                             const char* attr
, String8
* outError
) 
 243     ssize_t idx 
= tree
.indexOfAttribute(ns
, attr
); 
 248     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 249         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 250             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 255     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 256     return str 
? String8(str
, len
) : String8(); 
 259 static String8 
getAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, String8
* outError
) 
 261     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 266     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 267         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 268             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 273     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 274     return str 
? String8(str
, len
) : String8(); 
 277 static int32_t getIntegerAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, 
 278         String8
* outError
, int32_t defValue 
= -1) 
 280     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 285     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 286         if (value
.dataType 
< Res_value::TYPE_FIRST_INT
 
 287                 || value
.dataType 
> Res_value::TYPE_LAST_INT
) { 
 288             if (outError 
!= NULL
) *outError 
= "attribute is not an integer value"; 
 295 static int32_t getResolvedIntegerAttribute(const ResTable
* resTable
, const ResXMLTree
& tree
, 
 296         uint32_t attrRes
, String8
* outError
, int32_t defValue 
= -1) 
 298     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 303     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 304         if (value
.dataType 
== Res_value::TYPE_REFERENCE
) { 
 305             resTable
->resolveReference(&value
, 0); 
 307         if (value
.dataType 
< Res_value::TYPE_FIRST_INT
 
 308                 || value
.dataType 
> Res_value::TYPE_LAST_INT
) { 
 309             if (outError 
!= NULL
) *outError 
= "attribute is not an integer value"; 
 316 static String8 
getResolvedAttribute(const ResTable
* resTable
, const ResXMLTree
& tree
, 
 317         uint32_t attrRes
, String8
* outError
) 
 319     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 324     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 325         if (value
.dataType 
== Res_value::TYPE_STRING
) { 
 327             const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 328             return str 
? String8(str
, len
) : String8(); 
 330         resTable
->resolveReference(&value
, 0); 
 331         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 332             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 337     const Res_value
* value2 
= &value
; 
 338     const char16_t* str 
= const_cast<ResTable
*>(resTable
)->valueToString(value2
, 0, NULL
, &len
); 
 339     return str 
? String8(str
, len
) : String8(); 
 342 // These are attribute resource constants for the platform, as found 
 345     LABEL_ATTR 
= 0x01010001, 
 346     ICON_ATTR 
= 0x01010002, 
 347     NAME_ATTR 
= 0x01010003, 
 348     DEBUGGABLE_ATTR 
= 0x0101000f, 
 349     VERSION_CODE_ATTR 
= 0x0101021b, 
 350     VERSION_NAME_ATTR 
= 0x0101021c, 
 351     SCREEN_ORIENTATION_ATTR 
= 0x0101001e, 
 352     MIN_SDK_VERSION_ATTR 
= 0x0101020c, 
 353     MAX_SDK_VERSION_ATTR 
= 0x01010271, 
 354     REQ_TOUCH_SCREEN_ATTR 
= 0x01010227, 
 355     REQ_KEYBOARD_TYPE_ATTR 
= 0x01010228, 
 356     REQ_HARD_KEYBOARD_ATTR 
= 0x01010229, 
 357     REQ_NAVIGATION_ATTR 
= 0x0101022a, 
 358     REQ_FIVE_WAY_NAV_ATTR 
= 0x01010232, 
 359     TARGET_SDK_VERSION_ATTR 
= 0x01010270, 
 360     TEST_ONLY_ATTR 
= 0x01010272, 
 361     ANY_DENSITY_ATTR 
= 0x0101026c, 
 362     GL_ES_VERSION_ATTR 
= 0x01010281, 
 363     SMALL_SCREEN_ATTR 
= 0x01010284, 
 364     NORMAL_SCREEN_ATTR 
= 0x01010285, 
 365     LARGE_SCREEN_ATTR 
= 0x01010286, 
 366     XLARGE_SCREEN_ATTR 
= 0x010102bf, 
 367     REQUIRED_ATTR 
= 0x0101028e, 
 368     SCREEN_SIZE_ATTR 
= 0x010102ca, 
 369     SCREEN_DENSITY_ATTR 
= 0x010102cb, 
 370     REQUIRES_SMALLEST_WIDTH_DP_ATTR 
= 0x01010364, 
 371     COMPATIBLE_WIDTH_LIMIT_DP_ATTR 
= 0x01010365, 
 372     LARGEST_WIDTH_LIMIT_DP_ATTR 
= 0x01010366, 
 373     PUBLIC_KEY_ATTR 
= 0x010103a6, 
 376 const char *getComponentName(String8 
&pkgName
, String8 
&componentName
) { 
 377     ssize_t idx 
= componentName
.find("."); 
 378     String8 
retStr(pkgName
); 
 380         retStr 
+= componentName
; 
 381     } else if (idx 
< 0) { 
 383         retStr 
+= componentName
; 
 385         return componentName
.string(); 
 387     return retStr
.string(); 
 390 static void printCompatibleScreens(ResXMLTree
& tree
) { 
 392     ResXMLTree::event_code_t code
; 
 395     printf("compatible-screens:"); 
 396     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 397         if (code 
== ResXMLTree::END_TAG
) { 
 404         if (code 
!= ResXMLTree::START_TAG
) { 
 408         String8 
tag(tree
.getElementName(&len
)); 
 409         if (tag 
== "screen") { 
 410             int32_t screenSize 
= getIntegerAttribute(tree
, 
 411                     SCREEN_SIZE_ATTR
, NULL
, -1); 
 412             int32_t screenDensity 
= getIntegerAttribute(tree
, 
 413                     SCREEN_DENSITY_ATTR
, NULL
, -1); 
 414             if (screenSize 
> 0 && screenDensity 
> 0) { 
 419                 printf("'%d/%d'", screenSize
, screenDensity
); 
 427  * Handle the "dump" command, to extract select data from an archive. 
 429 extern char CONSOLE_DATA
[2925]; // see EOF 
 430 int doDump(Bundle
* bundle
) 
 432     status_t result 
= UNKNOWN_ERROR
; 
 435     if (bundle
->getFileSpecCount() < 1) { 
 436         fprintf(stderr
, "ERROR: no dump option specified\n"); 
 440     if (bundle
->getFileSpecCount() < 2) { 
 441         fprintf(stderr
, "ERROR: no dump file specified\n"); 
 445     const char* option 
= bundle
->getFileSpecEntry(0); 
 446     const char* filename 
= bundle
->getFileSpecEntry(1); 
 450     if (!assets
.addAssetPath(String8(filename
), &assetsCookie
)) { 
 451         fprintf(stderr
, "ERROR: dump failed because assets could not be loaded\n"); 
 455     // Make a dummy config for retrieving resources...  we need to supply 
 456     // non-default values for some configs so that we can retrieve resources 
 457     // in the app that don't have a default.  The most important of these is 
 458     // the API version because key resources like icons will have an implicit 
 459     // version if they are using newer config types like density. 
 460     ResTable_config config
; 
 461     config
.language
[0] = 'e'; 
 462     config
.language
[1] = 'n'; 
 463     config
.country
[0] = 'U'; 
 464     config
.country
[1] = 'S'; 
 465     config
.orientation 
= ResTable_config::ORIENTATION_PORT
; 
 466     config
.density 
= ResTable_config::DENSITY_MEDIUM
; 
 467     config
.sdkVersion 
= 10000; // Very high. 
 468     config
.screenWidthDp 
= 320; 
 469     config
.screenHeightDp 
= 480; 
 470     config
.smallestScreenWidthDp 
= 320; 
 471     assets
.setConfiguration(config
); 
 473     const ResTable
& res 
= assets
.getResources(false); 
 475         fprintf(stderr
, "ERROR: dump failed because no resource table was found\n"); 
 479     if (strcmp("resources", option
) == 0) { 
 480 #ifndef HAVE_ANDROID_OS 
 481         res
.print(bundle
->getValues()); 
 484     } else if (strcmp("strings", option
) == 0) { 
 485         const ResStringPool
* pool 
= res
.getTableStringBlock(0); 
 486         printStringPool(pool
); 
 488     } else if (strcmp("xmltree", option
) == 0) { 
 489         if (bundle
->getFileSpecCount() < 3) { 
 490             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 494         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 495             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 497             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 499                 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
); 
 503             if (tree
.setTo(asset
->getBuffer(true), 
 504                            asset
->getLength()) != NO_ERROR
) { 
 505                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 509             printXMLBlock(&tree
); 
 515     } else if (strcmp("xmlstrings", option
) == 0) { 
 516         if (bundle
->getFileSpecCount() < 3) { 
 517             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 521         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 522             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 524             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 526                 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
); 
 530             if (tree
.setTo(asset
->getBuffer(true), 
 531                            asset
->getLength()) != NO_ERROR
) { 
 532                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 535             printStringPool(&tree
.getStrings()); 
 542         asset 
= assets
.openNonAsset("AndroidManifest.xml", 
 543                                             Asset::ACCESS_BUFFER
); 
 545             fprintf(stderr
, "ERROR: dump failed because no AndroidManifest.xml found\n"); 
 549         if (tree
.setTo(asset
->getBuffer(true), 
 550                        asset
->getLength()) != NO_ERROR
) { 
 551             fprintf(stderr
, "ERROR: AndroidManifest.xml is corrupt\n"); 
 556         if (strcmp("permissions", option
) == 0) { 
 558             ResXMLTree::event_code_t code
; 
 560             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 561                 if (code 
== ResXMLTree::END_TAG
) { 
 565                 if (code 
!= ResXMLTree::START_TAG
) { 
 569                 String8 
tag(tree
.getElementName(&len
)); 
 570                 //printf("Depth %d tag %s\n", depth, tag.string()); 
 572                     if (tag 
!= "manifest") { 
 573                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 576                     String8 pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 577                     printf("package: %s\n", pkg
.string()); 
 578                 } else if (depth 
== 2 && tag 
== "permission") { 
 580                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 582                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 585                     printf("permission: %s\n", name
.string()); 
 586                 } else if (depth 
== 2 && tag 
== "uses-permission") { 
 588                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 590                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 593                     printf("uses-permission: %s\n", name
.string()); 
 596         } else if (strcmp("badging", option
) == 0) { 
 597             Vector
<String8
> locales
; 
 598             res
.getLocales(&locales
); 
 600             Vector
<ResTable_config
> configs
; 
 601             res
.getConfigurations(&configs
); 
 602             SortedVector
<int> densities
; 
 603             const size_t NC 
= configs
.size(); 
 604             for (size_t i
=0; i
<NC
; i
++) { 
 605                 int dens 
= configs
[i
].density
; 
 606                 if (dens 
== 0) dens 
= 160; 
 611             ResXMLTree::event_code_t code
; 
 614             bool withinActivity 
= false; 
 615             bool isMainActivity 
= false; 
 616             bool isLauncherActivity 
= false; 
 617             bool isSearchable 
= false; 
 618             bool withinApplication 
= false; 
 619             bool withinReceiver 
= false; 
 620             bool withinService 
= false; 
 621             bool withinIntentFilter 
= false; 
 622             bool hasMainActivity 
= false; 
 623             bool hasOtherActivities 
= false; 
 624             bool hasOtherReceivers 
= false; 
 625             bool hasOtherServices 
= false; 
 626             bool hasWallpaperService 
= false; 
 627             bool hasImeService 
= false; 
 628             bool hasWidgetReceivers 
= false; 
 629             bool hasIntentFilter 
= false; 
 630             bool actMainActivity 
= false; 
 631             bool actWidgetReceivers 
= false; 
 632             bool actImeService 
= false; 
 633             bool actWallpaperService 
= false; 
 635             // These two implement the implicit permissions that are granted 
 636             // to pre-1.6 applications. 
 637             bool hasWriteExternalStoragePermission 
= false; 
 638             bool hasReadPhoneStatePermission 
= false; 
 640             // If an app requests write storage, they will also get read storage. 
 641             bool hasReadExternalStoragePermission 
= false; 
 643             // Implement transition to read and write call log. 
 644             bool hasReadContactsPermission 
= false; 
 645             bool hasWriteContactsPermission 
= false; 
 646             bool hasReadCallLogPermission 
= false; 
 647             bool hasWriteCallLogPermission 
= false; 
 649             // This next group of variables is used to implement a group of 
 650             // backward-compatibility heuristics necessitated by the addition of 
 651             // some new uses-feature constants in 2.1 and 2.2. In most cases, the 
 652             // heuristic is "if an app requests a permission but doesn't explicitly 
 653             // request the corresponding <uses-feature>, presume it's there anyway". 
 654             bool specCameraFeature 
= false; // camera-related 
 655             bool specCameraAutofocusFeature 
= false; 
 656             bool reqCameraAutofocusFeature 
= false; 
 657             bool reqCameraFlashFeature 
= false; 
 658             bool hasCameraPermission 
= false; 
 659             bool specLocationFeature 
= false; // location-related 
 660             bool specNetworkLocFeature 
= false; 
 661             bool reqNetworkLocFeature 
= false; 
 662             bool specGpsFeature 
= false; 
 663             bool reqGpsFeature 
= false; 
 664             bool hasMockLocPermission 
= false; 
 665             bool hasCoarseLocPermission 
= false; 
 666             bool hasGpsPermission 
= false; 
 667             bool hasGeneralLocPermission 
= false; 
 668             bool specBluetoothFeature 
= false; // Bluetooth API-related 
 669             bool hasBluetoothPermission 
= false; 
 670             bool specMicrophoneFeature 
= false; // microphone-related 
 671             bool hasRecordAudioPermission 
= false; 
 672             bool specWiFiFeature 
= false; 
 673             bool hasWiFiPermission 
= false; 
 674             bool specTelephonyFeature 
= false; // telephony-related 
 675             bool reqTelephonySubFeature 
= false; 
 676             bool hasTelephonyPermission 
= false; 
 677             bool specTouchscreenFeature 
= false; // touchscreen-related 
 678             bool specMultitouchFeature 
= false; 
 679             bool reqDistinctMultitouchFeature 
= false; 
 680             bool specScreenPortraitFeature 
= false; 
 681             bool specScreenLandscapeFeature 
= false; 
 682             bool reqScreenPortraitFeature 
= false; 
 683             bool reqScreenLandscapeFeature 
= false; 
 684             // 2.2 also added some other features that apps can request, but that 
 685             // have no corresponding permission, so we cannot implement any 
 686             // back-compatibility heuristic for them. The below are thus unnecessary 
 687             // (but are retained here for documentary purposes.) 
 688             //bool specCompassFeature = false; 
 689             //bool specAccelerometerFeature = false; 
 690             //bool specProximityFeature = false; 
 691             //bool specAmbientLightFeature = false; 
 692             //bool specLiveWallpaperFeature = false; 
 696             int normalScreen 
= 1; 
 698             int xlargeScreen 
= 1; 
 700             int requiresSmallestWidthDp 
= 0; 
 701             int compatibleWidthLimitDp 
= 0; 
 702             int largestWidthLimitDp 
= 0; 
 704             String8 activityName
; 
 705             String8 activityLabel
; 
 706             String8 activityIcon
; 
 707             String8 receiverName
; 
 709             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 710                 if (code 
== ResXMLTree::END_TAG
) { 
 713                         withinApplication 
= false; 
 714                     } else if (depth 
< 3) { 
 715                         if (withinActivity 
&& isMainActivity 
&& isLauncherActivity
) { 
 716                             const char *aName 
= getComponentName(pkg
, activityName
); 
 717                             printf("launchable-activity:"); 
 719                                 printf(" name='%s' ", aName
); 
 721                             printf(" label='%s' icon='%s'\n", 
 722                                     activityLabel
.string(), 
 723                                     activityIcon
.string()); 
 725                         if (!hasIntentFilter
) { 
 726                             hasOtherActivities 
|= withinActivity
; 
 727                             hasOtherReceivers 
|= withinReceiver
; 
 728                             hasOtherServices 
|= withinService
; 
 730                         withinActivity 
= false; 
 731                         withinService 
= false; 
 732                         withinReceiver 
= false; 
 733                         hasIntentFilter 
= false; 
 734                         isMainActivity 
= isLauncherActivity 
= false; 
 735                     } else if (depth 
< 4) { 
 736                         if (withinIntentFilter
) { 
 737                             if (withinActivity
) { 
 738                                 hasMainActivity 
|= actMainActivity
; 
 739                                 hasOtherActivities 
|= !actMainActivity
; 
 740                             } else if (withinReceiver
) { 
 741                                 hasWidgetReceivers 
|= actWidgetReceivers
; 
 742                                 hasOtherReceivers 
|= !actWidgetReceivers
; 
 743                             } else if (withinService
) { 
 744                                 hasImeService 
|= actImeService
; 
 745                                 hasWallpaperService 
|= actWallpaperService
; 
 746                                 hasOtherServices 
|= (!actImeService 
&& !actWallpaperService
); 
 749                         withinIntentFilter 
= false; 
 753                 if (code 
!= ResXMLTree::START_TAG
) { 
 757                 String8 
tag(tree
.getElementName(&len
)); 
 758                 //printf("Depth %d,  %s\n", depth, tag.string()); 
 760                     if (tag 
!= "manifest") { 
 761                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 764                     pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 765                     printf("package: name='%s' ", pkg
.string()); 
 766                     int32_t versionCode 
= getIntegerAttribute(tree
, VERSION_CODE_ATTR
, &error
); 
 768                         fprintf(stderr
, "ERROR getting 'android:versionCode' attribute: %s\n", error
.string()); 
 771                     if (versionCode 
> 0) { 
 772                         printf("versionCode='%d' ", versionCode
); 
 774                         printf("versionCode='' "); 
 776                     String8 versionName 
= getResolvedAttribute(&res
, tree
, VERSION_NAME_ATTR
, &error
); 
 778                         fprintf(stderr
, "ERROR getting 'android:versionName' attribute: %s\n", error
.string()); 
 781                     printf("versionName='%s'\n", versionName
.string()); 
 782                 } else if (depth 
== 2) { 
 783                     withinApplication 
= false; 
 784                     if (tag 
== "application") { 
 785                         withinApplication 
= true; 
 788                         const size_t NL 
= locales
.size(); 
 789                         for (size_t i
=0; i
<NL
; i
++) { 
 790                             const char* localeStr 
=  locales
[i
].string(); 
 791                             assets
.setLocale(localeStr 
!= NULL 
? localeStr 
: ""); 
 792                             String8 llabel 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 794                                 if (localeStr 
== NULL 
|| strlen(localeStr
) == 0) { 
 796                                     printf("application-label:'%s'\n", llabel
.string()); 
 801                                     printf("application-label-%s:'%s'\n", localeStr
, 
 807                         ResTable_config tmpConfig 
= config
; 
 808                         const size_t ND 
= densities
.size(); 
 809                         for (size_t i
=0; i
<ND
; i
++) { 
 810                             tmpConfig
.density 
= densities
[i
]; 
 811                             assets
.setConfiguration(tmpConfig
); 
 812                             String8 icon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 814                                 printf("application-icon-%d:'%s'\n", densities
[i
], icon
.string()); 
 817                         assets
.setConfiguration(config
); 
 819                         String8 icon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 821                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 824                         int32_t testOnly 
= getIntegerAttribute(tree
, TEST_ONLY_ATTR
, &error
, 0); 
 826                             fprintf(stderr
, "ERROR getting 'android:testOnly' attribute: %s\n", error
.string()); 
 829                         printf("application: label='%s' ", label
.string()); 
 830                         printf("icon='%s'\n", icon
.string()); 
 832                             printf("testOnly='%d'\n", testOnly
); 
 835                         int32_t debuggable 
= getResolvedIntegerAttribute(&res
, tree
, DEBUGGABLE_ATTR
, &error
, 0); 
 837                             fprintf(stderr
, "ERROR getting 'android:debuggable' attribute: %s\n", error
.string()); 
 840                         if (debuggable 
!= 0) { 
 841                             printf("application-debuggable\n"); 
 843                     } else if (tag 
== "uses-sdk") { 
 844                         int32_t code 
= getIntegerAttribute(tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 847                             String8 name 
= getResolvedAttribute(&res
, tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 849                                 fprintf(stderr
, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 
 853                             if (name 
== "Donut") targetSdk 
= 4; 
 854                             printf("sdkVersion:'%s'\n", name
.string()); 
 855                         } else if (code 
!= -1) { 
 857                             printf("sdkVersion:'%d'\n", code
); 
 859                         code 
= getIntegerAttribute(tree
, MAX_SDK_VERSION_ATTR
, NULL
, -1); 
 861                             printf("maxSdkVersion:'%d'\n", code
); 
 863                         code 
= getIntegerAttribute(tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 866                             String8 name 
= getResolvedAttribute(&res
, tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 868                                 fprintf(stderr
, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 
 872                             if (name 
== "Donut" && targetSdk 
< 4) targetSdk 
= 4; 
 873                             printf("targetSdkVersion:'%s'\n", name
.string()); 
 874                         } else if (code 
!= -1) { 
 875                             if (targetSdk 
< code
) { 
 878                             printf("targetSdkVersion:'%d'\n", code
); 
 880                     } else if (tag 
== "uses-configuration") { 
 881                         int32_t reqTouchScreen 
= getIntegerAttribute(tree
, 
 882                                 REQ_TOUCH_SCREEN_ATTR
, NULL
, 0); 
 883                         int32_t reqKeyboardType 
= getIntegerAttribute(tree
, 
 884                                 REQ_KEYBOARD_TYPE_ATTR
, NULL
, 0); 
 885                         int32_t reqHardKeyboard 
= getIntegerAttribute(tree
, 
 886                                 REQ_HARD_KEYBOARD_ATTR
, NULL
, 0); 
 887                         int32_t reqNavigation 
= getIntegerAttribute(tree
, 
 888                                 REQ_NAVIGATION_ATTR
, NULL
, 0); 
 889                         int32_t reqFiveWayNav 
= getIntegerAttribute(tree
, 
 890                                 REQ_FIVE_WAY_NAV_ATTR
, NULL
, 0); 
 891                         printf("uses-configuration:"); 
 892                         if (reqTouchScreen 
!= 0) { 
 893                             printf(" reqTouchScreen='%d'", reqTouchScreen
); 
 895                         if (reqKeyboardType 
!= 0) { 
 896                             printf(" reqKeyboardType='%d'", reqKeyboardType
); 
 898                         if (reqHardKeyboard 
!= 0) { 
 899                             printf(" reqHardKeyboard='%d'", reqHardKeyboard
); 
 901                         if (reqNavigation 
!= 0) { 
 902                             printf(" reqNavigation='%d'", reqNavigation
); 
 904                         if (reqFiveWayNav 
!= 0) { 
 905                             printf(" reqFiveWayNav='%d'", reqFiveWayNav
); 
 908                     } else if (tag 
== "supports-screens") { 
 909                         smallScreen 
= getIntegerAttribute(tree
, 
 910                                 SMALL_SCREEN_ATTR
, NULL
, 1); 
 911                         normalScreen 
= getIntegerAttribute(tree
, 
 912                                 NORMAL_SCREEN_ATTR
, NULL
, 1); 
 913                         largeScreen 
= getIntegerAttribute(tree
, 
 914                                 LARGE_SCREEN_ATTR
, NULL
, 1); 
 915                         xlargeScreen 
= getIntegerAttribute(tree
, 
 916                                 XLARGE_SCREEN_ATTR
, NULL
, 1); 
 917                         anyDensity 
= getIntegerAttribute(tree
, 
 918                                 ANY_DENSITY_ATTR
, NULL
, 1); 
 919                         requiresSmallestWidthDp 
= getIntegerAttribute(tree
, 
 920                                 REQUIRES_SMALLEST_WIDTH_DP_ATTR
, NULL
, 0); 
 921                         compatibleWidthLimitDp 
= getIntegerAttribute(tree
, 
 922                                 COMPATIBLE_WIDTH_LIMIT_DP_ATTR
, NULL
, 0); 
 923                         largestWidthLimitDp 
= getIntegerAttribute(tree
, 
 924                                 LARGEST_WIDTH_LIMIT_DP_ATTR
, NULL
, 0); 
 925                     } else if (tag 
== "uses-feature") { 
 926                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 928                         if (name 
!= "" && error 
== "") { 
 929                             int req 
= getIntegerAttribute(tree
, 
 930                                     REQUIRED_ATTR
, NULL
, 1); 
 932                             if (name 
== "android.hardware.camera") { 
 933                                 specCameraFeature 
= true; 
 934                             } else if (name 
== "android.hardware.camera.autofocus") { 
 935                                 // these have no corresponding permission to check for, 
 936                                 // but should imply the foundational camera permission 
 937                                 reqCameraAutofocusFeature 
= reqCameraAutofocusFeature 
|| req
; 
 938                                 specCameraAutofocusFeature 
= true; 
 939                             } else if (req 
&& (name 
== "android.hardware.camera.flash")) { 
 940                                 // these have no corresponding permission to check for, 
 941                                 // but should imply the foundational camera permission 
 942                                 reqCameraFlashFeature 
= true; 
 943                             } else if (name 
== "android.hardware.location") { 
 944                                 specLocationFeature 
= true; 
 945                             } else if (name 
== "android.hardware.location.network") { 
 946                                 specNetworkLocFeature 
= true; 
 947                                 reqNetworkLocFeature 
= reqNetworkLocFeature 
|| req
; 
 948                             } else if (name 
== "android.hardware.location.gps") { 
 949                                 specGpsFeature 
= true; 
 950                                 reqGpsFeature 
= reqGpsFeature 
|| req
; 
 951                             } else if (name 
== "android.hardware.bluetooth") { 
 952                                 specBluetoothFeature 
= true; 
 953                             } else if (name 
== "android.hardware.touchscreen") { 
 954                                 specTouchscreenFeature 
= true; 
 955                             } else if (name 
== "android.hardware.touchscreen.multitouch") { 
 956                                 specMultitouchFeature 
= true; 
 957                             } else if (name 
== "android.hardware.touchscreen.multitouch.distinct") { 
 958                                 reqDistinctMultitouchFeature 
= reqDistinctMultitouchFeature 
|| req
; 
 959                             } else if (name 
== "android.hardware.microphone") { 
 960                                 specMicrophoneFeature 
= true; 
 961                             } else if (name 
== "android.hardware.wifi") { 
 962                                 specWiFiFeature 
= true; 
 963                             } else if (name 
== "android.hardware.telephony") { 
 964                                 specTelephonyFeature 
= true; 
 965                             } else if (req 
&& (name 
== "android.hardware.telephony.gsm" || 
 966                                                name 
== "android.hardware.telephony.cdma")) { 
 967                                 // these have no corresponding permission to check for, 
 968                                 // but should imply the foundational telephony permission 
 969                                 reqTelephonySubFeature 
= true; 
 970                             } else if (name 
== "android.hardware.screen.portrait") { 
 971                                 specScreenPortraitFeature 
= true; 
 972                             } else if (name 
== "android.hardware.screen.landscape") { 
 973                                 specScreenLandscapeFeature 
= true; 
 975                             printf("uses-feature%s:'%s'\n", 
 976                                     req 
? "" : "-not-required", name
.string()); 
 978                             int vers 
= getIntegerAttribute(tree
, 
 979                                     GL_ES_VERSION_ATTR
, &error
); 
 981                                 printf("uses-gl-es:'0x%x'\n", vers
); 
 984                     } else if (tag 
== "uses-permission") { 
 985                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 986                         if (name 
!= "" && error 
== "") { 
 987                             if (name 
== "android.permission.CAMERA") { 
 988                                 hasCameraPermission 
= true; 
 989                             } else if (name 
== "android.permission.ACCESS_FINE_LOCATION") { 
 990                                 hasGpsPermission 
= true; 
 991                             } else if (name 
== "android.permission.ACCESS_MOCK_LOCATION") { 
 992                                 hasMockLocPermission 
= true; 
 993                             } else if (name 
== "android.permission.ACCESS_COARSE_LOCATION") { 
 994                                 hasCoarseLocPermission 
= true; 
 995                             } else if (name 
== "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || 
 996                                        name 
== "android.permission.INSTALL_LOCATION_PROVIDER") { 
 997                                 hasGeneralLocPermission 
= true; 
 998                             } else if (name 
== "android.permission.BLUETOOTH" || 
 999                                        name 
== "android.permission.BLUETOOTH_ADMIN") { 
1000                                 hasBluetoothPermission 
= true; 
1001                             } else if (name 
== "android.permission.RECORD_AUDIO") { 
1002                                 hasRecordAudioPermission 
= true; 
1003                             } else if (name 
== "android.permission.ACCESS_WIFI_STATE" || 
1004                                        name 
== "android.permission.CHANGE_WIFI_STATE" || 
1005                                        name 
== "android.permission.CHANGE_WIFI_MULTICAST_STATE") { 
1006                                 hasWiFiPermission 
= true; 
1007                             } else if (name 
== "android.permission.CALL_PHONE" || 
1008                                        name 
== "android.permission.CALL_PRIVILEGED" || 
1009                                        name 
== "android.permission.MODIFY_PHONE_STATE" || 
1010                                        name 
== "android.permission.PROCESS_OUTGOING_CALLS" || 
1011                                        name 
== "android.permission.READ_SMS" || 
1012                                        name 
== "android.permission.RECEIVE_SMS" || 
1013                                        name 
== "android.permission.RECEIVE_MMS" || 
1014                                        name 
== "android.permission.RECEIVE_WAP_PUSH" || 
1015                                        name 
== "android.permission.SEND_SMS" || 
1016                                        name 
== "android.permission.WRITE_APN_SETTINGS" || 
1017                                        name 
== "android.permission.WRITE_SMS") { 
1018                                 hasTelephonyPermission 
= true; 
1019                             } else if (name 
== "android.permission.WRITE_EXTERNAL_STORAGE") { 
1020                                 hasWriteExternalStoragePermission 
= true; 
1021                             } else if (name 
== "android.permission.READ_EXTERNAL_STORAGE") { 
1022                                 hasReadExternalStoragePermission 
= true; 
1023                             } else if (name 
== "android.permission.READ_PHONE_STATE") { 
1024                                 hasReadPhoneStatePermission 
= true; 
1025                             } else if (name 
== "android.permission.READ_CONTACTS") { 
1026                                 hasReadContactsPermission 
= true; 
1027                             } else if (name 
== "android.permission.WRITE_CONTACTS") { 
1028                                 hasWriteContactsPermission 
= true; 
1029                             } else if (name 
== "android.permission.READ_CALL_LOG") { 
1030                                 hasReadCallLogPermission 
= true; 
1031                             } else if (name 
== "android.permission.WRITE_CALL_LOG") { 
1032                                 hasWriteCallLogPermission 
= true; 
1034                             printf("uses-permission:'%s'\n", name
.string()); 
1036                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
1040                     } else if (tag 
== "uses-package") { 
1041                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1042                         if (name 
!= "" && error 
== "") { 
1043                             printf("uses-package:'%s'\n", name
.string()); 
1045                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
1049                     } else if (tag 
== "original-package") { 
1050                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1051                         if (name 
!= "" && error 
== "") { 
1052                             printf("original-package:'%s'\n", name
.string()); 
1054                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
1058                     } else if (tag 
== "supports-gl-texture") { 
1059                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1060                         if (name 
!= "" && error 
== "") { 
1061                             printf("supports-gl-texture:'%s'\n", name
.string()); 
1063                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
1067                     } else if (tag 
== "compatible-screens") { 
1068                         printCompatibleScreens(tree
); 
1070                     } else if (tag 
== "package-verifier") { 
1071                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1072                         if (name 
!= "" && error 
== "") { 
1073                             String8 publicKey 
= getAttribute(tree
, PUBLIC_KEY_ATTR
, &error
); 
1074                             if (publicKey 
!= "" && error 
== "") { 
1075                                 printf("package-verifier: name='%s' publicKey='%s'\n", 
1076                                         name
.string(), publicKey
.string()); 
1080                 } else if (depth 
== 3 && withinApplication
) { 
1081                     withinActivity 
= false; 
1082                     withinReceiver 
= false; 
1083                     withinService 
= false; 
1084                     hasIntentFilter 
= false; 
1085                     if(tag 
== "activity") { 
1086                         withinActivity 
= true; 
1087                         activityName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1089                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
1093                         activityLabel 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
1095                             fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
1099                         activityIcon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
1101                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
1105                         int32_t orien 
= getResolvedIntegerAttribute(&res
, tree
, 
1106                                 SCREEN_ORIENTATION_ATTR
, &error
); 
1108                             if (orien 
== 0 || orien 
== 6 || orien 
== 8) { 
1109                                 // Requests landscape, sensorLandscape, or reverseLandscape. 
1110                                 reqScreenLandscapeFeature 
= true; 
1111                             } else if (orien 
== 1 || orien 
== 7 || orien 
== 9) { 
1112                                 // Requests portrait, sensorPortrait, or reversePortrait. 
1113                                 reqScreenPortraitFeature 
= true; 
1116                     } else if (tag 
== "uses-library") { 
1117                         String8 libraryName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1119                             fprintf(stderr
, "ERROR getting 'android:name' attribute for uses-library: %s\n", error
.string()); 
1122                         int req 
= getIntegerAttribute(tree
, 
1123                                 REQUIRED_ATTR
, NULL
, 1); 
1124                         printf("uses-library%s:'%s'\n", 
1125                                 req 
? "" : "-not-required", libraryName
.string()); 
1126                     } else if (tag 
== "receiver") { 
1127                         withinReceiver 
= true; 
1128                         receiverName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1131                             fprintf(stderr
, "ERROR getting 'android:name' attribute for receiver: %s\n", error
.string()); 
1134                     } else if (tag 
== "service") { 
1135                         withinService 
= true; 
1136                         serviceName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1139                             fprintf(stderr
, "ERROR getting 'android:name' attribute for service: %s\n", error
.string()); 
1143                 } else if ((depth 
== 4) && (tag 
== "intent-filter")) { 
1144                     hasIntentFilter 
= true; 
1145                     withinIntentFilter 
= true; 
1146                     actMainActivity 
= actWidgetReceivers 
= actImeService 
= actWallpaperService 
= false; 
1147                 } else if ((depth 
== 5) && withinIntentFilter
){ 
1149                     if (tag 
== "action") { 
1150                         action 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1152                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
1155                         if (withinActivity
) { 
1156                             if (action 
== "android.intent.action.MAIN") { 
1157                                 isMainActivity 
= true; 
1158                                 actMainActivity 
= true; 
1160                         } else if (withinReceiver
) { 
1161                             if (action 
== "android.appwidget.action.APPWIDGET_UPDATE") { 
1162                                 actWidgetReceivers 
= true; 
1164                         } else if (withinService
) { 
1165                             if (action 
== "android.view.InputMethod") { 
1166                                 actImeService 
= true; 
1167                             } else if (action 
== "android.service.wallpaper.WallpaperService") { 
1168                                 actWallpaperService 
= true; 
1171                         if (action 
== "android.intent.action.SEARCH") { 
1172                             isSearchable 
= true; 
1176                     if (tag 
== "category") { 
1177                         String8 category 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1179                             fprintf(stderr
, "ERROR getting 'name' attribute: %s\n", error
.string()); 
1182                         if (withinActivity
) { 
1183                             if (category 
== "android.intent.category.LAUNCHER") { 
1184                                 isLauncherActivity 
= true; 
1191             // Pre-1.6 implicitly granted permission compatibility logic 
1192             if (targetSdk 
< 4) { 
1193                 if (!hasWriteExternalStoragePermission
) { 
1194                     printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n"); 
1195                     hasWriteExternalStoragePermission 
= true; 
1197                 if (!hasReadPhoneStatePermission
) { 
1198                     printf("uses-permission:'android.permission.READ_PHONE_STATE'\n"); 
1202             // If the application has requested WRITE_EXTERNAL_STORAGE, we will 
1203             // force them to always take READ_EXTERNAL_STORAGE as well. 
1204             if (!hasReadExternalStoragePermission 
&& hasWriteExternalStoragePermission
) { 
1205                 printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n"); 
1208             // Pre-JellyBean call log permission compatibility. 
1209             if (targetSdk 
< 16) { 
1210                 if (!hasReadCallLogPermission 
&& hasReadContactsPermission
) { 
1211                     printf("uses-permission:'android.permission.READ_CALL_LOG'\n"); 
1213                 if (!hasWriteCallLogPermission 
&& hasWriteContactsPermission
) { 
1214                     printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n"); 
1218             /* The following blocks handle printing "inferred" uses-features, based 
1219              * on whether related features or permissions are used by the app. 
1220              * Note that the various spec*Feature variables denote whether the 
1221              * relevant tag was *present* in the AndroidManfest, not that it was 
1222              * present and set to true. 
1224             // Camera-related back-compatibility logic 
1225             if (!specCameraFeature
) { 
1226                 if (reqCameraFlashFeature 
|| reqCameraAutofocusFeature
) { 
1227                     // if app requested a sub-feature (autofocus or flash) and didn't 
1228                     // request the base camera feature, we infer that it meant to 
1229                     printf("uses-feature:'android.hardware.camera'\n"); 
1230                 } else if (hasCameraPermission
) { 
1231                     // if app wants to use camera but didn't request the feature, we infer  
1232                     // that it meant to, and further that it wants autofocus 
1233                     // (which was the 1.0 - 1.5 behavior) 
1234                     printf("uses-feature:'android.hardware.camera'\n"); 
1235                     if (!specCameraAutofocusFeature
) { 
1236                         printf("uses-feature:'android.hardware.camera.autofocus'\n"); 
1241             // Location-related back-compatibility logic 
1242             if (!specLocationFeature 
&& 
1243                 (hasMockLocPermission 
|| hasCoarseLocPermission 
|| hasGpsPermission 
|| 
1244                  hasGeneralLocPermission 
|| reqNetworkLocFeature 
|| reqGpsFeature
)) { 
1245                 // if app either takes a location-related permission or requests one of the 
1246                 // sub-features, we infer that it also meant to request the base location feature 
1247                 printf("uses-feature:'android.hardware.location'\n"); 
1249             if (!specGpsFeature 
&& hasGpsPermission
) { 
1250                 // if app takes GPS (FINE location) perm but does not request the GPS 
1251                 // feature, we infer that it meant to 
1252                 printf("uses-feature:'android.hardware.location.gps'\n"); 
1254             if (!specNetworkLocFeature 
&& hasCoarseLocPermission
) { 
1255                 // if app takes Network location (COARSE location) perm but does not request the 
1256                 // network location feature, we infer that it meant to 
1257                 printf("uses-feature:'android.hardware.location.network'\n"); 
1260             // Bluetooth-related compatibility logic 
1261             if (!specBluetoothFeature 
&& hasBluetoothPermission 
&& (targetSdk 
> 4)) { 
1262                 // if app takes a Bluetooth permission but does not request the Bluetooth 
1263                 // feature, we infer that it meant to 
1264                 printf("uses-feature:'android.hardware.bluetooth'\n"); 
1267             // Microphone-related compatibility logic 
1268             if (!specMicrophoneFeature 
&& hasRecordAudioPermission
) { 
1269                 // if app takes the record-audio permission but does not request the microphone 
1270                 // feature, we infer that it meant to 
1271                 printf("uses-feature:'android.hardware.microphone'\n"); 
1274             // WiFi-related compatibility logic 
1275             if (!specWiFiFeature 
&& hasWiFiPermission
) { 
1276                 // if app takes one of the WiFi permissions but does not request the WiFi 
1277                 // feature, we infer that it meant to 
1278                 printf("uses-feature:'android.hardware.wifi'\n"); 
1281             // Telephony-related compatibility logic 
1282             if (!specTelephonyFeature 
&& (hasTelephonyPermission 
|| reqTelephonySubFeature
)) { 
1283                 // if app takes one of the telephony permissions or requests a sub-feature but 
1284                 // does not request the base telephony feature, we infer that it meant to 
1285                 printf("uses-feature:'android.hardware.telephony'\n"); 
1288             // Touchscreen-related back-compatibility logic 
1289             if (!specTouchscreenFeature
) { // not a typo! 
1290                 // all apps are presumed to require a touchscreen, unless they explicitly say 
1291                 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 
1292                 // Note that specTouchscreenFeature is true if the tag is present, regardless 
1293                 // of whether its value is true or false, so this is safe 
1294                 printf("uses-feature:'android.hardware.touchscreen'\n"); 
1296             if (!specMultitouchFeature 
&& reqDistinctMultitouchFeature
) { 
1297                 // if app takes one of the telephony permissions or requests a sub-feature but 
1298                 // does not request the base telephony feature, we infer that it meant to 
1299                 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 
1302             // Landscape/portrait-related compatibility logic 
1303             if (!specScreenLandscapeFeature 
&& !specScreenPortraitFeature
) { 
1304                 // If the app has specified any activities in its manifest 
1305                 // that request a specific orientation, then assume that 
1306                 // orientation is required. 
1307                 if (reqScreenLandscapeFeature
) { 
1308                     printf("uses-feature:'android.hardware.screen.landscape'\n"); 
1310                 if (reqScreenPortraitFeature
) { 
1311                     printf("uses-feature:'android.hardware.screen.portrait'\n"); 
1315             if (hasMainActivity
) { 
1318             if (hasWidgetReceivers
) { 
1319                 printf("app-widget\n"); 
1321             if (hasImeService
) { 
1324             if (hasWallpaperService
) { 
1325                 printf("wallpaper\n"); 
1327             if (hasOtherActivities
) { 
1328                 printf("other-activities\n"); 
1333             if (hasOtherReceivers
) { 
1334                 printf("other-receivers\n"); 
1336             if (hasOtherServices
) { 
1337                 printf("other-services\n"); 
1340             // For modern apps, if screen size buckets haven't been specified 
1341             // but the new width ranges have, then infer the buckets from them. 
1342             if (smallScreen 
> 0 && normalScreen 
> 0 && largeScreen 
> 0 && xlargeScreen 
> 0 
1343                     && requiresSmallestWidthDp 
> 0) { 
1344                 int compatWidth 
= compatibleWidthLimitDp
; 
1345                 if (compatWidth 
<= 0) compatWidth 
= requiresSmallestWidthDp
; 
1346                 if (requiresSmallestWidthDp 
<= 240 && compatWidth 
>= 240) { 
1351                 if (requiresSmallestWidthDp 
<= 320 && compatWidth 
>= 320) { 
1356                 if (requiresSmallestWidthDp 
<= 480 && compatWidth 
>= 480) { 
1361                 if (requiresSmallestWidthDp 
<= 720 && compatWidth 
>= 720) { 
1368             // Determine default values for any unspecified screen sizes, 
1369             // based on the target SDK of the package.  As of 4 (donut) 
1370             // the screen size support was introduced, so all default to 
1372             if (smallScreen 
> 0) { 
1373                 smallScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1375             if (normalScreen 
> 0) { 
1378             if (largeScreen 
> 0) { 
1379                 largeScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1381             if (xlargeScreen 
> 0) { 
1382                 // Introduced in Gingerbread. 
1383                 xlargeScreen 
= targetSdk 
>= 9 ? -1 : 0; 
1385             if (anyDensity 
> 0) { 
1386                 anyDensity 
= (targetSdk 
>= 4 || requiresSmallestWidthDp 
> 0 
1387                         || compatibleWidthLimitDp 
> 0) ? -1 : 0; 
1389             printf("supports-screens:"); 
1390             if (smallScreen 
!= 0) printf(" 'small'"); 
1391             if (normalScreen 
!= 0) printf(" 'normal'"); 
1392             if (largeScreen 
!= 0) printf(" 'large'"); 
1393             if (xlargeScreen 
!= 0) printf(" 'xlarge'"); 
1395             printf("supports-any-density: '%s'\n", anyDensity 
? "true" : "false"); 
1396             if (requiresSmallestWidthDp 
> 0) { 
1397                 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp
); 
1399             if (compatibleWidthLimitDp 
> 0) { 
1400                 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp
); 
1402             if (largestWidthLimitDp 
> 0) { 
1403                 printf("largest-width-limit:'%d'\n", largestWidthLimitDp
); 
1407             const size_t NL 
= locales
.size(); 
1408             for (size_t i
=0; i
<NL
; i
++) { 
1409                 const char* localeStr 
=  locales
[i
].string(); 
1410                 if (localeStr 
== NULL 
|| strlen(localeStr
) == 0) { 
1411                     localeStr 
= "--_--"; 
1413                 printf(" '%s'", localeStr
); 
1417             printf("densities:"); 
1418             const size_t ND 
= densities
.size(); 
1419             for (size_t i
=0; i
<ND
; i
++) { 
1420                 printf(" '%d'", densities
[i
]); 
1424             AssetDir
* dir 
= assets
.openNonAssetDir(assetsCookie
, "lib"); 
1426                 if (dir
->getFileCount() > 0) { 
1427                     printf("native-code:"); 
1428                     for (size_t i
=0; i
<dir
->getFileCount(); i
++) { 
1429                         printf(" '%s'", dir
->getFileName(i
).string()); 
1435         } else if (strcmp("badger", option
) == 0) { 
1436             printf("%s", CONSOLE_DATA
); 
1437         } else if (strcmp("configurations", option
) == 0) { 
1438             Vector
<ResTable_config
> configs
; 
1439             res
.getConfigurations(&configs
); 
1440             const size_t N 
= configs
.size(); 
1441             for (size_t i
=0; i
<N
; i
++) { 
1442                 printf("%s\n", configs
[i
].toString().string()); 
1445             fprintf(stderr
, "ERROR: unknown dump option '%s'\n", option
); 
1456     return (result 
!= NO_ERROR
); 
1461  * Handle the "add" command, which wants to add files to a new or 
1462  * pre-existing archive. 
1464 int doAdd(Bundle
* bundle
) 
1466     ZipFile
* zip 
= NULL
; 
1467     status_t result 
= UNKNOWN_ERROR
; 
1468     const char* zipFileName
; 
1470     if (bundle
->getUpdate()) { 
1471         /* avoid confusion */ 
1472         fprintf(stderr
, "ERROR: can't use '-u' with add\n"); 
1476     if (bundle
->getFileSpecCount() < 1) { 
1477         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1480     zipFileName 
= bundle
->getFileSpecEntry(0); 
1482     if (bundle
->getFileSpecCount() < 2) { 
1483         fprintf(stderr
, "NOTE: nothing to do\n"); 
1487     zip 
= openReadWrite(zipFileName
, true); 
1489         fprintf(stderr
, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName
); 
1493     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1494         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1496         if (strcasecmp(String8(fileName
).getPathExtension().string(), ".gz") == 0) { 
1497             printf(" '%s'... (from gzip)\n", fileName
); 
1498             result 
= zip
->addGzip(fileName
, String8(fileName
).getBasePath().string(), NULL
); 
1500             if (bundle
->getJunkPath()) { 
1501                 String8 storageName 
= String8(fileName
).getPathLeaf(); 
1502                 printf(" '%s' as '%s'...\n", fileName
, storageName
.string()); 
1503                 result 
= zip
->add(fileName
, storageName
.string(), 
1504                                   bundle
->getCompressionMethod(), NULL
); 
1506                 printf(" '%s'...\n", fileName
); 
1507                 result 
= zip
->add(fileName
, bundle
->getCompressionMethod(), NULL
); 
1510         if (result 
!= NO_ERROR
) { 
1511             fprintf(stderr
, "Unable to add '%s' to '%s'", bundle
->getFileSpecEntry(i
), zipFileName
); 
1512             if (result 
== NAME_NOT_FOUND
) 
1513                 fprintf(stderr
, ": file not found\n"); 
1514             else if (result 
== ALREADY_EXISTS
) 
1515                 fprintf(stderr
, ": already exists in archive\n"); 
1517                 fprintf(stderr
, "\n"); 
1526     return (result 
!= NO_ERROR
); 
1531  * Delete files from an existing archive. 
1533 int doRemove(Bundle
* bundle
) 
1535     ZipFile
* zip 
= NULL
; 
1536     status_t result 
= UNKNOWN_ERROR
; 
1537     const char* zipFileName
; 
1539     if (bundle
->getFileSpecCount() < 1) { 
1540         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1543     zipFileName 
= bundle
->getFileSpecEntry(0); 
1545     if (bundle
->getFileSpecCount() < 2) { 
1546         fprintf(stderr
, "NOTE: nothing to do\n"); 
1550     zip 
= openReadWrite(zipFileName
, false); 
1552         fprintf(stderr
, "ERROR: failed opening Zip archive '%s'\n", 
1557     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1558         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1561         entry 
= zip
->getEntryByName(fileName
); 
1562         if (entry 
== NULL
) { 
1563             printf(" '%s' NOT FOUND\n", fileName
); 
1567         result 
= zip
->remove(entry
); 
1569         if (result 
!= NO_ERROR
) { 
1570             fprintf(stderr
, "Unable to delete '%s' from '%s'\n", 
1571                 bundle
->getFileSpecEntry(i
), zipFileName
); 
1576     /* update the archive */ 
1581     return (result 
!= NO_ERROR
); 
1586  * Package up an asset directory and associated application files. 
1588 int doPackage(Bundle
* bundle
) 
1590     const char* outputAPKFile
; 
1593     sp
<AaptAssets
> assets
; 
1596     String8 dependencyFile
; 
1598     // -c zz_ZZ means do pseudolocalization 
1599     ResourceFilter filter
; 
1600     err 
= filter
.parse(bundle
->getConfigurations()); 
1601     if (err 
!= NO_ERROR
) { 
1604     if (filter
.containsPseudo()) { 
1605         bundle
->setPseudolocalize(true); 
1608     N 
= bundle
->getFileSpecCount(); 
1609     if (N 
< 1 && bundle
->getResourceSourceDirs().size() == 0 && bundle
->getJarFiles().size() == 0 
1610             && bundle
->getAndroidManifestFile() == NULL 
&& bundle
->getAssetSourceDir() == NULL
) { 
1611         fprintf(stderr
, "ERROR: no input files\n"); 
1615     outputAPKFile 
= bundle
->getOutputAPKFile(); 
1617     // Make sure the filenames provided exist and are of the appropriate type. 
1618     if (outputAPKFile
) { 
1620         type 
= getFileType(outputAPKFile
); 
1621         if (type 
!= kFileTypeNonexistent 
&& type 
!= kFileTypeRegular
) { 
1623                 "ERROR: output file '%s' exists but is not regular file\n", 
1630     assets 
= new AaptAssets(); 
1632     // Set up the resource gathering in assets if we're going to generate 
1633     // dependency files. Every time we encounter a resource while slurping 
1634     // the tree, we'll add it to these stores so we have full resource paths 
1635     // to write to a dependency file. 
1636     if (bundle
->getGenDependencies()) { 
1637         sp
<FilePathStore
> resPathStore 
= new FilePathStore
; 
1638         assets
->setFullResPaths(resPathStore
); 
1639         sp
<FilePathStore
> assetPathStore 
= new FilePathStore
; 
1640         assets
->setFullAssetPaths(assetPathStore
); 
1643     err 
= assets
->slurpFromArgs(bundle
); 
1648     if (bundle
->getVerbose()) { 
1649         assets
->print(String8()); 
1652     // If they asked for any fileAs that need to be compiled, do so. 
1653     if (bundle
->getResourceSourceDirs().size() || bundle
->getAndroidManifestFile()) { 
1654         err 
= buildResources(bundle
, assets
); 
1660     // At this point we've read everything and processed everything.  From here 
1661     // on out it's just writing output files. 
1662     if (SourcePos::hasErrors()) { 
1666     // Update symbols with information about which ones are needed as Java symbols. 
1667     assets
->applyJavaSymbols(); 
1668     if (SourcePos::hasErrors()) { 
1672     // If we've been asked to generate a dependency file, do that here 
1673     if (bundle
->getGenDependencies()) { 
1674         // If this is the packaging step, generate the dependency file next to 
1675         // the output apk (e.g. bin/resources.ap_.d) 
1676         if (outputAPKFile
) { 
1677             dependencyFile 
= String8(outputAPKFile
); 
1678             // Add the .d extension to the dependency file. 
1679             dependencyFile
.append(".d"); 
1681             // Else if this is the R.java dependency generation step, 
1682             // generate the dependency file in the R.java package subdirectory 
1683             // e.g. gen/com/foo/app/R.java.d 
1684             dependencyFile 
= String8(bundle
->getRClassDir()); 
1685             dependencyFile
.appendPath("R.java.d"); 
1687         // Make sure we have a clean dependency file to start with 
1688         fp 
= fopen(dependencyFile
, "w"); 
1692     // Write out R.java constants 
1693     if (!assets
->havePrivateSymbols()) { 
1694         if (bundle
->getCustomPackage() == NULL
) { 
1695             // Write the R.java file into the appropriate class directory 
1696             // e.g. gen/com/foo/app/R.java 
1697             err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), true); 
1698             // If we have library files, we're going to write our R.java file into 
1699             // the appropriate class directory for those libraries as well. 
1700             // e.g. gen/com/foo/app/lib/R.java 
1701             if (bundle
->getExtraPackages() != NULL
) { 
1703                 String8 
libs(bundle
->getExtraPackages()); 
1704                 char* packageString 
= strtok(libs
.lockBuffer(libs
.length()), ":"); 
1705                 while (packageString 
!= NULL
) { 
1706                     // Write the R.java file out with the correct package name 
1707                     err 
= writeResourceSymbols(bundle
, assets
, String8(packageString
), true); 
1708                     packageString 
= strtok(NULL
, ":"); 
1710                 libs
.unlockBuffer(); 
1713             const String8 
customPkg(bundle
->getCustomPackage()); 
1714             err 
= writeResourceSymbols(bundle
, assets
, customPkg
, true); 
1720         err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), false); 
1724         err 
= writeResourceSymbols(bundle
, assets
, assets
->getSymbolsPrivatePackage(), true); 
1730     // Write out the ProGuard file 
1731     err 
= writeProguardFile(bundle
, assets
); 
1737     if (outputAPKFile
) { 
1738         err 
= writeAPK(bundle
, assets
, String8(outputAPKFile
)); 
1739         if (err 
!= NO_ERROR
) { 
1740             fprintf(stderr
, "ERROR: packaging of '%s' failed\n", outputAPKFile
); 
1745     // If we've been asked to generate a dependency file, we need to finish up here. 
1746     // the writeResourceSymbols and writeAPK functions have already written the target 
1747     // half of the dependency file, now we need to write the prerequisites. (files that 
1748     // the R.java file or .ap_ file depend on) 
1749     if (bundle
->getGenDependencies()) { 
1750         // Now that writeResourceSymbols or writeAPK has taken care of writing 
1751         // the targets to our dependency file, we'll write the prereqs 
1752         fp 
= fopen(dependencyFile
, "a+"); 
1754         bool includeRaw 
= (outputAPKFile 
!= NULL
); 
1755         err 
= writeDependencyPreReqs(bundle
, assets
, fp
, includeRaw
); 
1756         // Also manually add the AndroidManifeset since it's not under res/ or assets/ 
1757         // and therefore was not added to our pathstores during slurping 
1758         fprintf(fp
, "%s \\\n", bundle
->getAndroidManifestFile()); 
1764     if (SourcePos::hasErrors()) { 
1765         SourcePos::printErrors(stderr
); 
1773  *  -S flag points to a source directory containing drawable* folders 
1774  *  -C flag points to destination directory. The folder structure in the 
1775  *     source directory will be mirrored to the destination (cache) directory 
1778  *  Destination directory will be updated to match the PNG files in 
1779  *  the source directory.  
1781 int doCrunch(Bundle
* bundle
) 
1783     fprintf(stdout
, "Crunching PNG Files in "); 
1784     fprintf(stdout
, "source dir: %s\n", bundle
->getResourceSourceDirs()[0]); 
1785     fprintf(stdout
, "To destination dir: %s\n", bundle
->getCrunchedOutputDir()); 
1787     updatePreProcessedCache(bundle
); 
1792 char CONSOLE_DATA
[2925] = { 
1793     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1794     32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1795     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1796     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 
1797     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 
1798     86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 
1799     62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1800     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1801     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 
1802     81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32, 
1803     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 
1804     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1805     32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59, 
1806     59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1807     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1808     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 
1809     59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32, 
1810     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1811     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1812     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 
1813     58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 
1814     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 
1815     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 
1816     47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 
1817     121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1818     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1819     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 
1820     81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 
1821     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 
1822     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1823     32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59, 
1824     59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1825     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1826     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59, 
1827     59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32, 
1828     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1829     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1830     32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, 
1831     70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 
1832     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 
1833     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1834     32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 
1835     81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1836     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1837     32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 
1838     81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 
1839     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 
1840     32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59, 
1841     59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59, 
1842     60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1843     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59, 
1844     61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46, 
1845     61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32, 
1846     46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1847     32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 
1848     59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81, 
1849     109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, 
1850     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 
1851     67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 
1852     59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 
1853     61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 
1854     32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 
1855     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 
1856     73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 
1857     59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 
1858     32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 
1859     59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96, 
1860     46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 
1861     97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32, 
1862     46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61, 
1863     119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59, 
1864     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32, 
1865     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1866     32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, 
1867     119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 
1868     59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 
1869     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1870     32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 
1871     81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 
1872     87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 
1873     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 
1874     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 
1875     45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32, 
1876     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1877     32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 
1878     81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 
1879     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 
1880     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 
1881     59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 
1882     59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1883     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1884     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, 
1885     81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 
1886     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1887     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1888     32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
1889     81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1890     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 
1891     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 
1892     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 
1893     32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1894     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1895     32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81, 
1896     81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 
1897     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 
1898     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1899     58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59, 
1900     61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1901     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1902     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81, 
1903     81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, 
1904     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1905     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1906     32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
1907     81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1908     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 
1909     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 
1910     59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 
1911     59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1912     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1913     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33, 
1914     58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 
1915     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 
1916     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 
1917     61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59, 
1918     59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 
1919     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 
1920     32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95, 
1921     32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59, 
1922     61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1923     32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1924     32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 
1925     59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 
1926     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 
1927     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 
1928     59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 
1929     59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1930     32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1931     32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 
1932     32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32, 
1933     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 
1934     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1935     46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61, 
1936     46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1937     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 
1938     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 
1939     59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59, 
1940     59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1941     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1942     32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 
1943     32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 
1944     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 
1945     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 
1946     59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 
1947     59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1948     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1949     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 
1950     32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 
1951     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1952     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1953     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1954     32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1955     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10