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                     printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \
 
1196                             "'targetSdkVersion < 4'\n"); 
1197                     hasWriteExternalStoragePermission 
= true; 
1199                 if (!hasReadPhoneStatePermission
) { 
1200                     printf("uses-permission:'android.permission.READ_PHONE_STATE'\n"); 
1201                     printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \
 
1202                             "'targetSdkVersion < 4'\n"); 
1206             // If the application has requested WRITE_EXTERNAL_STORAGE, we will 
1207             // force them to always take READ_EXTERNAL_STORAGE as well. 
1208             if (!hasReadExternalStoragePermission 
&& hasWriteExternalStoragePermission
) { 
1209                 printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n"); 
1210                 printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \
 
1211                         "'requested WRITE_EXTERNAL_STORAGE'\n"); 
1214             // Pre-JellyBean call log permission compatibility. 
1215             if (targetSdk 
< 16) { 
1216                 if (!hasReadCallLogPermission 
&& hasReadContactsPermission
) { 
1217                     printf("uses-permission:'android.permission.READ_CALL_LOG'\n"); 
1218                     printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \
 
1219                             "'targetSdkVersion < 16 and requested READ_CONTACTS'\n"); 
1221                 if (!hasWriteCallLogPermission 
&& hasWriteContactsPermission
) { 
1222                     printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n"); 
1223                     printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \
 
1224                             "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n"); 
1228             /* The following blocks handle printing "inferred" uses-features, based 
1229              * on whether related features or permissions are used by the app. 
1230              * Note that the various spec*Feature variables denote whether the 
1231              * relevant tag was *present* in the AndroidManfest, not that it was 
1232              * present and set to true. 
1234             // Camera-related back-compatibility logic 
1235             if (!specCameraFeature
) { 
1236                 if (reqCameraFlashFeature
) { 
1237                     // if app requested a sub-feature (autofocus or flash) and didn't 
1238                     // request the base camera feature, we infer that it meant to 
1239                     printf("uses-feature:'android.hardware.camera'\n"); 
1240                     printf("uses-implied-feature:'android.hardware.camera'," \
 
1241                             "'requested android.hardware.camera.flash feature'\n"); 
1242                 } else if (reqCameraAutofocusFeature
) { 
1243                     // if app requested a sub-feature (autofocus or flash) and didn't 
1244                     // request the base camera feature, we infer that it meant to 
1245                     printf("uses-feature:'android.hardware.camera'\n"); 
1246                     printf("uses-implied-feature:'android.hardware.camera'," \
 
1247                             "'requested android.hardware.camera.autofocus feature'\n"); 
1248                 } else if (hasCameraPermission
) { 
1249                     // if app wants to use camera but didn't request the feature, we infer  
1250                     // that it meant to, and further that it wants autofocus 
1251                     // (which was the 1.0 - 1.5 behavior) 
1252                     printf("uses-feature:'android.hardware.camera'\n"); 
1253                     if (!specCameraAutofocusFeature
) { 
1254                         printf("uses-feature:'android.hardware.camera.autofocus'\n"); 
1255                         printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
 
1256                                 "'requested android.permission.CAMERA permission'\n"); 
1261             // Location-related back-compatibility logic 
1262             if (!specLocationFeature 
&& 
1263                 (hasMockLocPermission 
|| hasCoarseLocPermission 
|| hasGpsPermission 
|| 
1264                  hasGeneralLocPermission 
|| reqNetworkLocFeature 
|| reqGpsFeature
)) { 
1265                 // if app either takes a location-related permission or requests one of the 
1266                 // sub-features, we infer that it also meant to request the base location feature 
1267                 printf("uses-feature:'android.hardware.location'\n"); 
1268                 printf("uses-implied-feature:'android.hardware.location'," \
 
1269                         "'requested a location access permission'\n"); 
1271             if (!specGpsFeature 
&& hasGpsPermission
) { 
1272                 // if app takes GPS (FINE location) perm but does not request the GPS 
1273                 // feature, we infer that it meant to 
1274                 printf("uses-feature:'android.hardware.location.gps'\n"); 
1275                 printf("uses-implied-feature:'android.hardware.location.gps'," \
 
1276                         "'requested android.permission.ACCESS_FINE_LOCATION permission'\n"); 
1278             if (!specNetworkLocFeature 
&& hasCoarseLocPermission
) { 
1279                 // if app takes Network location (COARSE location) perm but does not request the 
1280                 // network location feature, we infer that it meant to 
1281                 printf("uses-feature:'android.hardware.location.network'\n"); 
1282                 printf("uses-implied-feature:'android.hardware.location.network'," \
 
1283                         "'requested android.permission.ACCESS_COURSE_LOCATION permission'\n"); 
1286             // Bluetooth-related compatibility logic 
1287             if (!specBluetoothFeature 
&& hasBluetoothPermission 
&& (targetSdk 
> 4)) { 
1288                 // if app takes a Bluetooth permission but does not request the Bluetooth 
1289                 // feature, we infer that it meant to 
1290                 printf("uses-feature:'android.hardware.bluetooth'\n"); 
1291                 printf("uses-implied-feature:'android.hardware.bluetooth'," \
 
1292                         "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
 
1293                         "permission and targetSdkVersion > 4'\n"); 
1296             // Microphone-related compatibility logic 
1297             if (!specMicrophoneFeature 
&& hasRecordAudioPermission
) { 
1298                 // if app takes the record-audio permission but does not request the microphone 
1299                 // feature, we infer that it meant to 
1300                 printf("uses-feature:'android.hardware.microphone'\n"); 
1301                 printf("uses-implied-feature:'android.hardware.microphone'," \
 
1302                         "'requested android.permission.RECORD_AUDIO permission'\n"); 
1305             // WiFi-related compatibility logic 
1306             if (!specWiFiFeature 
&& hasWiFiPermission
) { 
1307                 // if app takes one of the WiFi permissions but does not request the WiFi 
1308                 // feature, we infer that it meant to 
1309                 printf("uses-feature:'android.hardware.wifi'\n"); 
1310                 printf("uses-implied-feature:'android.hardware.wifi'," \
 
1311                         "'requested android.permission.ACCESS_WIFI_STATE, " \
 
1312                         "android.permission.CHANGE_WIFI_STATE, or " \
 
1313                         "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n"); 
1316             // Telephony-related compatibility logic 
1317             if (!specTelephonyFeature 
&& (hasTelephonyPermission 
|| reqTelephonySubFeature
)) { 
1318                 // if app takes one of the telephony permissions or requests a sub-feature but 
1319                 // does not request the base telephony feature, we infer that it meant to 
1320                 printf("uses-feature:'android.hardware.telephony'\n"); 
1321                 printf("uses-implied-feature:'android.hardware.telephony'," \
 
1322                         "'requested a telephony-related permission or feature'\n"); 
1325             // Touchscreen-related back-compatibility logic 
1326             if (!specTouchscreenFeature
) { // not a typo! 
1327                 // all apps are presumed to require a touchscreen, unless they explicitly say 
1328                 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 
1329                 // Note that specTouchscreenFeature is true if the tag is present, regardless 
1330                 // of whether its value is true or false, so this is safe 
1331                 printf("uses-feature:'android.hardware.touchscreen'\n"); 
1332                 printf("uses-implied-feature:'android.hardware.touchscreen'," \
 
1333                         "'assumed you require a touch screen unless explicitly made optional'\n"); 
1335             if (!specMultitouchFeature 
&& reqDistinctMultitouchFeature
) { 
1336                 // if app takes one of the telephony permissions or requests a sub-feature but 
1337                 // does not request the base telephony feature, we infer that it meant to 
1338                 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 
1339                 printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
 
1340                         "'requested android.hardware.touchscreen.multitouch.distinct feature'\n"); 
1343             // Landscape/portrait-related compatibility logic 
1344             if (!specScreenLandscapeFeature 
&& !specScreenPortraitFeature
) { 
1345                 // If the app has specified any activities in its manifest 
1346                 // that request a specific orientation, then assume that 
1347                 // orientation is required. 
1348                 if (reqScreenLandscapeFeature
) { 
1349                     printf("uses-feature:'android.hardware.screen.landscape'\n"); 
1350                     printf("uses-implied-feature:'android.hardware.screen.landscape'," \
 
1351                             "'one or more activities have specified a landscape orientation'\n"); 
1353                 if (reqScreenPortraitFeature
) { 
1354                     printf("uses-feature:'android.hardware.screen.portrait'\n"); 
1355                     printf("uses-implied-feature:'android.hardware.screen.portrait'," \
 
1356                             "'one or more activities have specified a portrait orientation'\n"); 
1360             if (hasMainActivity
) { 
1363             if (hasWidgetReceivers
) { 
1364                 printf("app-widget\n"); 
1366             if (hasImeService
) { 
1369             if (hasWallpaperService
) { 
1370                 printf("wallpaper\n"); 
1372             if (hasOtherActivities
) { 
1373                 printf("other-activities\n"); 
1378             if (hasOtherReceivers
) { 
1379                 printf("other-receivers\n"); 
1381             if (hasOtherServices
) { 
1382                 printf("other-services\n"); 
1385             // For modern apps, if screen size buckets haven't been specified 
1386             // but the new width ranges have, then infer the buckets from them. 
1387             if (smallScreen 
> 0 && normalScreen 
> 0 && largeScreen 
> 0 && xlargeScreen 
> 0 
1388                     && requiresSmallestWidthDp 
> 0) { 
1389                 int compatWidth 
= compatibleWidthLimitDp
; 
1390                 if (compatWidth 
<= 0) compatWidth 
= requiresSmallestWidthDp
; 
1391                 if (requiresSmallestWidthDp 
<= 240 && compatWidth 
>= 240) { 
1396                 if (requiresSmallestWidthDp 
<= 320 && compatWidth 
>= 320) { 
1401                 if (requiresSmallestWidthDp 
<= 480 && compatWidth 
>= 480) { 
1406                 if (requiresSmallestWidthDp 
<= 720 && compatWidth 
>= 720) { 
1413             // Determine default values for any unspecified screen sizes, 
1414             // based on the target SDK of the package.  As of 4 (donut) 
1415             // the screen size support was introduced, so all default to 
1417             if (smallScreen 
> 0) { 
1418                 smallScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1420             if (normalScreen 
> 0) { 
1423             if (largeScreen 
> 0) { 
1424                 largeScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1426             if (xlargeScreen 
> 0) { 
1427                 // Introduced in Gingerbread. 
1428                 xlargeScreen 
= targetSdk 
>= 9 ? -1 : 0; 
1430             if (anyDensity 
> 0) { 
1431                 anyDensity 
= (targetSdk 
>= 4 || requiresSmallestWidthDp 
> 0 
1432                         || compatibleWidthLimitDp 
> 0) ? -1 : 0; 
1434             printf("supports-screens:"); 
1435             if (smallScreen 
!= 0) printf(" 'small'"); 
1436             if (normalScreen 
!= 0) printf(" 'normal'"); 
1437             if (largeScreen 
!= 0) printf(" 'large'"); 
1438             if (xlargeScreen 
!= 0) printf(" 'xlarge'"); 
1440             printf("supports-any-density: '%s'\n", anyDensity 
? "true" : "false"); 
1441             if (requiresSmallestWidthDp 
> 0) { 
1442                 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp
); 
1444             if (compatibleWidthLimitDp 
> 0) { 
1445                 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp
); 
1447             if (largestWidthLimitDp 
> 0) { 
1448                 printf("largest-width-limit:'%d'\n", largestWidthLimitDp
); 
1452             const size_t NL 
= locales
.size(); 
1453             for (size_t i
=0; i
<NL
; i
++) { 
1454                 const char* localeStr 
=  locales
[i
].string(); 
1455                 if (localeStr 
== NULL 
|| strlen(localeStr
) == 0) { 
1456                     localeStr 
= "--_--"; 
1458                 printf(" '%s'", localeStr
); 
1462             printf("densities:"); 
1463             const size_t ND 
= densities
.size(); 
1464             for (size_t i
=0; i
<ND
; i
++) { 
1465                 printf(" '%d'", densities
[i
]); 
1469             AssetDir
* dir 
= assets
.openNonAssetDir(assetsCookie
, "lib"); 
1471                 if (dir
->getFileCount() > 0) { 
1472                     printf("native-code:"); 
1473                     for (size_t i
=0; i
<dir
->getFileCount(); i
++) { 
1474                         printf(" '%s'", dir
->getFileName(i
).string()); 
1480         } else if (strcmp("badger", option
) == 0) { 
1481             printf("%s", CONSOLE_DATA
); 
1482         } else if (strcmp("configurations", option
) == 0) { 
1483             Vector
<ResTable_config
> configs
; 
1484             res
.getConfigurations(&configs
); 
1485             const size_t N 
= configs
.size(); 
1486             for (size_t i
=0; i
<N
; i
++) { 
1487                 printf("%s\n", configs
[i
].toString().string()); 
1490             fprintf(stderr
, "ERROR: unknown dump option '%s'\n", option
); 
1501     return (result 
!= NO_ERROR
); 
1506  * Handle the "add" command, which wants to add files to a new or 
1507  * pre-existing archive. 
1509 int doAdd(Bundle
* bundle
) 
1511     ZipFile
* zip 
= NULL
; 
1512     status_t result 
= UNKNOWN_ERROR
; 
1513     const char* zipFileName
; 
1515     if (bundle
->getUpdate()) { 
1516         /* avoid confusion */ 
1517         fprintf(stderr
, "ERROR: can't use '-u' with add\n"); 
1521     if (bundle
->getFileSpecCount() < 1) { 
1522         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1525     zipFileName 
= bundle
->getFileSpecEntry(0); 
1527     if (bundle
->getFileSpecCount() < 2) { 
1528         fprintf(stderr
, "NOTE: nothing to do\n"); 
1532     zip 
= openReadWrite(zipFileName
, true); 
1534         fprintf(stderr
, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName
); 
1538     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1539         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1541         if (strcasecmp(String8(fileName
).getPathExtension().string(), ".gz") == 0) { 
1542             printf(" '%s'... (from gzip)\n", fileName
); 
1543             result 
= zip
->addGzip(fileName
, String8(fileName
).getBasePath().string(), NULL
); 
1545             if (bundle
->getJunkPath()) { 
1546                 String8 storageName 
= String8(fileName
).getPathLeaf(); 
1547                 printf(" '%s' as '%s'...\n", fileName
, storageName
.string()); 
1548                 result 
= zip
->add(fileName
, storageName
.string(), 
1549                                   bundle
->getCompressionMethod(), NULL
); 
1551                 printf(" '%s'...\n", fileName
); 
1552                 result 
= zip
->add(fileName
, bundle
->getCompressionMethod(), NULL
); 
1555         if (result 
!= NO_ERROR
) { 
1556             fprintf(stderr
, "Unable to add '%s' to '%s'", bundle
->getFileSpecEntry(i
), zipFileName
); 
1557             if (result 
== NAME_NOT_FOUND
) 
1558                 fprintf(stderr
, ": file not found\n"); 
1559             else if (result 
== ALREADY_EXISTS
) 
1560                 fprintf(stderr
, ": already exists in archive\n"); 
1562                 fprintf(stderr
, "\n"); 
1571     return (result 
!= NO_ERROR
); 
1576  * Delete files from an existing archive. 
1578 int doRemove(Bundle
* bundle
) 
1580     ZipFile
* zip 
= NULL
; 
1581     status_t result 
= UNKNOWN_ERROR
; 
1582     const char* zipFileName
; 
1584     if (bundle
->getFileSpecCount() < 1) { 
1585         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1588     zipFileName 
= bundle
->getFileSpecEntry(0); 
1590     if (bundle
->getFileSpecCount() < 2) { 
1591         fprintf(stderr
, "NOTE: nothing to do\n"); 
1595     zip 
= openReadWrite(zipFileName
, false); 
1597         fprintf(stderr
, "ERROR: failed opening Zip archive '%s'\n", 
1602     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1603         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1606         entry 
= zip
->getEntryByName(fileName
); 
1607         if (entry 
== NULL
) { 
1608             printf(" '%s' NOT FOUND\n", fileName
); 
1612         result 
= zip
->remove(entry
); 
1614         if (result 
!= NO_ERROR
) { 
1615             fprintf(stderr
, "Unable to delete '%s' from '%s'\n", 
1616                 bundle
->getFileSpecEntry(i
), zipFileName
); 
1621     /* update the archive */ 
1626     return (result 
!= NO_ERROR
); 
1631  * Package up an asset directory and associated application files. 
1633 int doPackage(Bundle
* bundle
) 
1635     const char* outputAPKFile
; 
1638     sp
<AaptAssets
> assets
; 
1641     String8 dependencyFile
; 
1643     // -c zz_ZZ means do pseudolocalization 
1644     ResourceFilter filter
; 
1645     err 
= filter
.parse(bundle
->getConfigurations()); 
1646     if (err 
!= NO_ERROR
) { 
1649     if (filter
.containsPseudo()) { 
1650         bundle
->setPseudolocalize(true); 
1653     N 
= bundle
->getFileSpecCount(); 
1654     if (N 
< 1 && bundle
->getResourceSourceDirs().size() == 0 && bundle
->getJarFiles().size() == 0 
1655             && bundle
->getAndroidManifestFile() == NULL 
&& bundle
->getAssetSourceDir() == NULL
) { 
1656         fprintf(stderr
, "ERROR: no input files\n"); 
1660     outputAPKFile 
= bundle
->getOutputAPKFile(); 
1662     // Make sure the filenames provided exist and are of the appropriate type. 
1663     if (outputAPKFile
) { 
1665         type 
= getFileType(outputAPKFile
); 
1666         if (type 
!= kFileTypeNonexistent 
&& type 
!= kFileTypeRegular
) { 
1668                 "ERROR: output file '%s' exists but is not regular file\n", 
1675     assets 
= new AaptAssets(); 
1677     // Set up the resource gathering in assets if we're going to generate 
1678     // dependency files. Every time we encounter a resource while slurping 
1679     // the tree, we'll add it to these stores so we have full resource paths 
1680     // to write to a dependency file. 
1681     if (bundle
->getGenDependencies()) { 
1682         sp
<FilePathStore
> resPathStore 
= new FilePathStore
; 
1683         assets
->setFullResPaths(resPathStore
); 
1684         sp
<FilePathStore
> assetPathStore 
= new FilePathStore
; 
1685         assets
->setFullAssetPaths(assetPathStore
); 
1688     err 
= assets
->slurpFromArgs(bundle
); 
1693     if (bundle
->getVerbose()) { 
1694         assets
->print(String8()); 
1697     // If they asked for any fileAs that need to be compiled, do so. 
1698     if (bundle
->getResourceSourceDirs().size() || bundle
->getAndroidManifestFile()) { 
1699         err 
= buildResources(bundle
, assets
); 
1705     // At this point we've read everything and processed everything.  From here 
1706     // on out it's just writing output files. 
1707     if (SourcePos::hasErrors()) { 
1711     // Update symbols with information about which ones are needed as Java symbols. 
1712     assets
->applyJavaSymbols(); 
1713     if (SourcePos::hasErrors()) { 
1717     // If we've been asked to generate a dependency file, do that here 
1718     if (bundle
->getGenDependencies()) { 
1719         // If this is the packaging step, generate the dependency file next to 
1720         // the output apk (e.g. bin/resources.ap_.d) 
1721         if (outputAPKFile
) { 
1722             dependencyFile 
= String8(outputAPKFile
); 
1723             // Add the .d extension to the dependency file. 
1724             dependencyFile
.append(".d"); 
1726             // Else if this is the R.java dependency generation step, 
1727             // generate the dependency file in the R.java package subdirectory 
1728             // e.g. gen/com/foo/app/R.java.d 
1729             dependencyFile 
= String8(bundle
->getRClassDir()); 
1730             dependencyFile
.appendPath("R.java.d"); 
1732         // Make sure we have a clean dependency file to start with 
1733         fp 
= fopen(dependencyFile
, "w"); 
1737     // Write out R.java constants 
1738     if (!assets
->havePrivateSymbols()) { 
1739         if (bundle
->getCustomPackage() == NULL
) { 
1740             // Write the R.java file into the appropriate class directory 
1741             // e.g. gen/com/foo/app/R.java 
1742             err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), true); 
1744             const String8 
customPkg(bundle
->getCustomPackage()); 
1745             err 
= writeResourceSymbols(bundle
, assets
, customPkg
, true); 
1750         // If we have library files, we're going to write our R.java file into 
1751         // the appropriate class directory for those libraries as well. 
1752         // e.g. gen/com/foo/app/lib/R.java 
1753         if (bundle
->getExtraPackages() != NULL
) { 
1755             String8 
libs(bundle
->getExtraPackages()); 
1756             char* packageString 
= strtok(libs
.lockBuffer(libs
.length()), ":"); 
1757             while (packageString 
!= NULL
) { 
1758                 // Write the R.java file out with the correct package name 
1759                 err 
= writeResourceSymbols(bundle
, assets
, String8(packageString
), true); 
1763                 packageString 
= strtok(NULL
, ":"); 
1765             libs
.unlockBuffer(); 
1768         err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), false); 
1772         err 
= writeResourceSymbols(bundle
, assets
, assets
->getSymbolsPrivatePackage(), true); 
1778     // Write out the ProGuard file 
1779     err 
= writeProguardFile(bundle
, assets
); 
1785     if (outputAPKFile
) { 
1786         err 
= writeAPK(bundle
, assets
, String8(outputAPKFile
)); 
1787         if (err 
!= NO_ERROR
) { 
1788             fprintf(stderr
, "ERROR: packaging of '%s' failed\n", outputAPKFile
); 
1793     // If we've been asked to generate a dependency file, we need to finish up here. 
1794     // the writeResourceSymbols and writeAPK functions have already written the target 
1795     // half of the dependency file, now we need to write the prerequisites. (files that 
1796     // the R.java file or .ap_ file depend on) 
1797     if (bundle
->getGenDependencies()) { 
1798         // Now that writeResourceSymbols or writeAPK has taken care of writing 
1799         // the targets to our dependency file, we'll write the prereqs 
1800         fp 
= fopen(dependencyFile
, "a+"); 
1802         bool includeRaw 
= (outputAPKFile 
!= NULL
); 
1803         err 
= writeDependencyPreReqs(bundle
, assets
, fp
, includeRaw
); 
1804         // Also manually add the AndroidManifeset since it's not under res/ or assets/ 
1805         // and therefore was not added to our pathstores during slurping 
1806         fprintf(fp
, "%s \\\n", bundle
->getAndroidManifestFile()); 
1812     if (SourcePos::hasErrors()) { 
1813         SourcePos::printErrors(stderr
); 
1821  *  -S flag points to a source directory containing drawable* folders 
1822  *  -C flag points to destination directory. The folder structure in the 
1823  *     source directory will be mirrored to the destination (cache) directory 
1826  *  Destination directory will be updated to match the PNG files in 
1827  *  the source directory.  
1829 int doCrunch(Bundle
* bundle
) 
1831     fprintf(stdout
, "Crunching PNG Files in "); 
1832     fprintf(stdout
, "source dir: %s\n", bundle
->getResourceSourceDirs()[0]); 
1833     fprintf(stdout
, "To destination dir: %s\n", bundle
->getCrunchedOutputDir()); 
1835     updatePreProcessedCache(bundle
); 
1840 char CONSOLE_DATA
[2925] = { 
1841     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1842     32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1843     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1844     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 
1845     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 
1846     86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 
1847     62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1848     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1849     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 
1850     81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32, 
1851     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 
1852     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1853     32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59, 
1854     59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1855     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1856     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 
1857     59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32, 
1858     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1859     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1860     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 
1861     58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 
1862     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 
1863     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 
1864     47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 
1865     121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1866     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1867     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 
1868     81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 
1869     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 
1870     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1871     32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59, 
1872     59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1873     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1874     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59, 
1875     59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32, 
1876     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1877     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1878     32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, 
1879     70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 
1880     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 
1881     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1882     32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 
1883     81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1884     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1885     32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 
1886     81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 
1887     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 
1888     32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59, 
1889     59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59, 
1890     60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1891     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59, 
1892     61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46, 
1893     61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32, 
1894     46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1895     32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 
1896     59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81, 
1897     109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, 
1898     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 
1899     67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 
1900     59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 
1901     61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 
1902     32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 
1903     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 
1904     73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 
1905     59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 
1906     32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 
1907     59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96, 
1908     46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 
1909     97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32, 
1910     46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61, 
1911     119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59, 
1912     59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32, 
1913     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1914     32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, 
1915     119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 
1916     59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 
1917     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1918     32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 
1919     81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 
1920     87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 
1921     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 
1922     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 
1923     45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32, 
1924     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1925     32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 
1926     81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 
1927     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 
1928     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 
1929     59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 
1930     59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1931     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1932     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, 
1933     81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 
1934     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1935     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1936     32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
1937     81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1938     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 
1939     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 
1940     81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 
1941     32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1942     32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1943     32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81, 
1944     81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 
1945     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 
1946     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1947     58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59, 
1948     61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1949     32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1950     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81, 
1951     81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, 
1952     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1953     32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1954     32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 
1955     81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1956     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 
1957     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 
1958     59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 
1959     59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1960     32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1961     32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33, 
1962     58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 
1963     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 
1964     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 
1965     61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59, 
1966     59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 
1967     32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 
1968     32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95, 
1969     32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59, 
1970     61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1971     32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1972     32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 
1973     59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 
1974     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 
1975     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 
1976     59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 
1977     59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1978     32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1979     32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 
1980     32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32, 
1981     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 
1982     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1983     46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61, 
1984     46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1985     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 
1986     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 
1987     59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59, 
1988     59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1989     32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1990     32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 
1991     32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 
1992     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 
1993     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 
1994     59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 
1995     59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1996     32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
1997     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 
1998     32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 
1999     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
2000     10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
2001     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
2002     32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
2003     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10