2 // Copyright 2006 The Android Open Source Project 
   4 // Android Asset Packaging Tool main entry point. 
   8 #include "ResourceTable.h" 
  11 #include <utils/Log.h> 
  12 #include <utils/threads.h> 
  13 #include <utils/List.h> 
  14 #include <utils/Errors.h> 
  19 using namespace android
; 
  22  * Show version info.  All the cool kids do it. 
  24 int doVersion(Bundle
* bundle
) 
  26     if (bundle
->getFileSpecCount() != 0) 
  27         printf("(ignoring extra arguments)\n"); 
  28     printf("Android Asset Packaging Tool, v0.2\n"); 
  35  * Open the file read only.  The call fails if the file doesn't exist. 
  37  * Returns NULL on failure. 
  39 ZipFile
* openReadOnly(const char* fileName
) 
  45     result 
= zip
->open(fileName
, ZipFile::kOpenReadOnly
); 
  46     if (result 
!= NO_ERROR
) { 
  47         if (result 
== NAME_NOT_FOUND
) 
  48             fprintf(stderr
, "ERROR: '%s' not found\n", fileName
); 
  49         else if (result 
== PERMISSION_DENIED
) 
  50             fprintf(stderr
, "ERROR: '%s' access denied\n", fileName
); 
  52             fprintf(stderr
, "ERROR: failed opening '%s' as Zip file\n", 
  62  * Open the file read-write.  The file will be created if it doesn't 
  63  * already exist and "okayToCreate" is set. 
  65  * Returns NULL on failure. 
  67 ZipFile
* openReadWrite(const char* fileName
, bool okayToCreate
) 
  73     flags 
= ZipFile::kOpenReadWrite
; 
  75         flags 
|= ZipFile::kOpenCreate
; 
  78     result 
= zip
->open(fileName
, flags
); 
  79     if (result 
!= NO_ERROR
) { 
  91  * Return a short string describing the compression method. 
  93 const char* compressionName(int method
) 
  95     if (method 
== ZipEntry::kCompressStored
) 
  97     else if (method 
== ZipEntry::kCompressDeflated
) 
 104  * Return the percent reduction in size (0% == no compression). 
 106 int calcPercent(long uncompressedLen
, long compressedLen
) 
 108     if (!uncompressedLen
) 
 111         return (int) (100.0 - (compressedLen 
* 100.0) / uncompressedLen 
+ 0.5); 
 115  * Handle the "list" command, which can be a simple file dump or 
 118  * The verbose listing closely matches the output of the Info-ZIP "unzip" 
 121 int doList(Bundle
* bundle
) 
 125     const ZipEntry
* entry
; 
 126     long totalUncLen
, totalCompLen
; 
 127     const char* zipFileName
; 
 129     if (bundle
->getFileSpecCount() != 1) { 
 130         fprintf(stderr
, "ERROR: specify zip file name (only)\n"); 
 133     zipFileName 
= bundle
->getFileSpecEntry(0); 
 135     zip 
= openReadOnly(zipFileName
); 
 141     if (bundle
->getVerbose()) { 
 142         printf("Archive:  %s\n", zipFileName
); 
 144             " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n"); 
 146             "--------  ------  ------- -----  -------      ----  ----  ------    ----\n"); 
 149     totalUncLen 
= totalCompLen 
= 0; 
 151     count 
= zip
->getNumEntries(); 
 152     for (i 
= 0; i 
< count
; i
++) { 
 153         entry 
= zip
->getEntryByIndex(i
); 
 154         if (bundle
->getVerbose()) { 
 158             when 
= entry
->getModWhen(); 
 159             strftime(dateBuf
, sizeof(dateBuf
), "%m-%d-%y %H:%M", 
 162             printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n", 
 163                 (long) entry
->getUncompressedLen(), 
 164                 compressionName(entry
->getCompressionMethod()), 
 165                 (long) entry
->getCompressedLen(), 
 166                 calcPercent(entry
->getUncompressedLen(), 
 167                             entry
->getCompressedLen()), 
 168                 (size_t) entry
->getLFHOffset(), 
 171                 entry
->getFileName()); 
 173             printf("%s\n", entry
->getFileName()); 
 176         totalUncLen 
+= entry
->getUncompressedLen(); 
 177         totalCompLen 
+= entry
->getCompressedLen(); 
 180     if (bundle
->getVerbose()) { 
 182         "--------          -------  ---                            -------\n"); 
 183         printf("%8ld          %7ld  %2d%%                            %d files\n", 
 186             calcPercent(totalUncLen
, totalCompLen
), 
 187             zip
->getNumEntries()); 
 190     if (bundle
->getAndroidList()) { 
 192         if (!assets
.addAssetPath(String8(zipFileName
), NULL
)) { 
 193             fprintf(stderr
, "ERROR: list -a failed because assets could not be loaded\n"); 
 197         const ResTable
& res 
= assets
.getResources(false); 
 199             printf("\nNo resource table found.\n"); 
 201 #ifndef HAVE_ANDROID_OS 
 202             printf("\nResource table:\n"); 
 207         Asset
* manifestAsset 
= assets
.openNonAsset("AndroidManifest.xml", 
 208                                                    Asset::ACCESS_BUFFER
); 
 209         if (manifestAsset 
== NULL
) { 
 210             printf("\nNo AndroidManifest.xml found.\n"); 
 212             printf("\nAndroid manifest:\n"); 
 214             tree
.setTo(manifestAsset
->getBuffer(true), 
 215                        manifestAsset
->getLength()); 
 216             printXMLBlock(&tree
); 
 218         delete manifestAsset
; 
 228 static ssize_t 
indexOfAttribute(const ResXMLTree
& tree
, uint32_t attrRes
) 
 230     size_t N 
= tree
.getAttributeCount(); 
 231     for (size_t i
=0; i
<N
; i
++) { 
 232         if (tree
.getAttributeNameResID(i
) == attrRes
) { 
 239 String8 
getAttribute(const ResXMLTree
& tree
, const char* ns
, 
 240                             const char* attr
, String8
* outError
) 
 242     ssize_t idx 
= tree
.indexOfAttribute(ns
, attr
); 
 247     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 248         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 249             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 254     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 255     return str 
? String8(str
, len
) : String8(); 
 258 static String8 
getAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, String8
* outError
) 
 260     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 265     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 266         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 267             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 272     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 273     return str 
? String8(str
, len
) : String8(); 
 276 static int32_t getIntegerAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, 
 277         String8
* outError
, int32_t defValue 
= -1) 
 279     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 284     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 285         if (value
.dataType 
< Res_value::TYPE_FIRST_INT
 
 286                 || value
.dataType 
> Res_value::TYPE_LAST_INT
) { 
 287             if (outError 
!= NULL
) *outError 
= "attribute is not an integer value"; 
 294 static String8 
getResolvedAttribute(const ResTable
* resTable
, const ResXMLTree
& tree
, 
 295         uint32_t attrRes
, String8
* outError
) 
 297     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 302     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 303         if (value
.dataType 
== Res_value::TYPE_STRING
) { 
 305             const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 306             return str 
? String8(str
, len
) : String8(); 
 308         resTable
->resolveReference(&value
, 0); 
 309         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 310             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 315     const Res_value
* value2 
= &value
; 
 316     const char16_t* str 
= const_cast<ResTable
*>(resTable
)->valueToString(value2
, 0, NULL
, &len
); 
 317     return str 
? String8(str
, len
) : String8(); 
 320 // These are attribute resource constants for the platform, as found 
 323     NAME_ATTR 
= 0x01010003, 
 324     VERSION_CODE_ATTR 
= 0x0101021b, 
 325     VERSION_NAME_ATTR 
= 0x0101021c, 
 326     LABEL_ATTR 
= 0x01010001, 
 327     ICON_ATTR 
= 0x01010002, 
 328     MIN_SDK_VERSION_ATTR 
= 0x0101020c, 
 329     MAX_SDK_VERSION_ATTR 
= 0x01010271, 
 330     REQ_TOUCH_SCREEN_ATTR 
= 0x01010227, 
 331     REQ_KEYBOARD_TYPE_ATTR 
= 0x01010228, 
 332     REQ_HARD_KEYBOARD_ATTR 
= 0x01010229, 
 333     REQ_NAVIGATION_ATTR 
= 0x0101022a, 
 334     REQ_FIVE_WAY_NAV_ATTR 
= 0x01010232, 
 335     TARGET_SDK_VERSION_ATTR 
= 0x01010270, 
 336     TEST_ONLY_ATTR 
= 0x01010272, 
 337     ANY_DENSITY_ATTR 
= 0x0101026c, 
 338     GL_ES_VERSION_ATTR 
= 0x01010281, 
 339     SMALL_SCREEN_ATTR 
= 0x01010284, 
 340     NORMAL_SCREEN_ATTR 
= 0x01010285, 
 341     LARGE_SCREEN_ATTR 
= 0x01010286, 
 342     XLARGE_SCREEN_ATTR 
= 0x010102bf, 
 343     REQUIRED_ATTR 
= 0x0101028e, 
 344     SCREEN_SIZE_ATTR 
= 0x010102ca, 
 345     SCREEN_DENSITY_ATTR 
= 0x010102cb, 
 348 const char *getComponentName(String8 
&pkgName
, String8 
&componentName
) { 
 349     ssize_t idx 
= componentName
.find("."); 
 350     String8 
retStr(pkgName
); 
 352         retStr 
+= componentName
; 
 353     } else if (idx 
< 0) { 
 355         retStr 
+= componentName
; 
 357         return componentName
.string(); 
 359     return retStr
.string(); 
 362 static void printCompatibleScreens(ResXMLTree
& tree
) { 
 364     ResXMLTree::event_code_t code
; 
 367     printf("compatible-screens:"); 
 368     while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 369         if (code 
== ResXMLTree::END_TAG
) { 
 376         if (code 
!= ResXMLTree::START_TAG
) { 
 380         String8 
tag(tree
.getElementName(&len
)); 
 381         if (tag 
== "screen") { 
 382             int32_t screenSize 
= getIntegerAttribute(tree
, 
 383                     SCREEN_SIZE_ATTR
, NULL
, -1); 
 384             int32_t screenDensity 
= getIntegerAttribute(tree
, 
 385                     SCREEN_DENSITY_ATTR
, NULL
, -1); 
 386             if (screenSize 
> 0 && screenDensity 
> 0) { 
 391                 printf("'%d/%d'", screenSize
, screenDensity
); 
 399  * Handle the "dump" command, to extract select data from an archive. 
 401 int doDump(Bundle
* bundle
) 
 403     status_t result 
= UNKNOWN_ERROR
; 
 406     if (bundle
->getFileSpecCount() < 1) { 
 407         fprintf(stderr
, "ERROR: no dump option specified\n"); 
 411     if (bundle
->getFileSpecCount() < 2) { 
 412         fprintf(stderr
, "ERROR: no dump file specified\n"); 
 416     const char* option 
= bundle
->getFileSpecEntry(0); 
 417     const char* filename 
= bundle
->getFileSpecEntry(1); 
 421     if (!assets
.addAssetPath(String8(filename
), &assetsCookie
)) { 
 422         fprintf(stderr
, "ERROR: dump failed because assets could not be loaded\n"); 
 426     const ResTable
& res 
= assets
.getResources(false); 
 428         fprintf(stderr
, "ERROR: dump failed because no resource table was found\n"); 
 432     if (strcmp("resources", option
) == 0) { 
 433 #ifndef HAVE_ANDROID_OS 
 434         res
.print(bundle
->getValues()); 
 436     } else if (strcmp("xmltree", option
) == 0) { 
 437         if (bundle
->getFileSpecCount() < 3) { 
 438             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 442         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 443             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 445             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 447                 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
); 
 451             if (tree
.setTo(asset
->getBuffer(true), 
 452                            asset
->getLength()) != NO_ERROR
) { 
 453                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 457             printXMLBlock(&tree
); 
 463     } else if (strcmp("xmlstrings", option
) == 0) { 
 464         if (bundle
->getFileSpecCount() < 3) { 
 465             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 469         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 470             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 472             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 474                 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
); 
 478             if (tree
.setTo(asset
->getBuffer(true), 
 479                            asset
->getLength()) != NO_ERROR
) { 
 480                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 483             printStringPool(&tree
.getStrings()); 
 490         asset 
= assets
.openNonAsset("AndroidManifest.xml", 
 491                                             Asset::ACCESS_BUFFER
); 
 493             fprintf(stderr
, "ERROR: dump failed because no AndroidManifest.xml found\n"); 
 497         if (tree
.setTo(asset
->getBuffer(true), 
 498                        asset
->getLength()) != NO_ERROR
) { 
 499             fprintf(stderr
, "ERROR: AndroidManifest.xml is corrupt\n"); 
 504         if (strcmp("permissions", option
) == 0) { 
 506             ResXMLTree::event_code_t code
; 
 508             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 509                 if (code 
== ResXMLTree::END_TAG
) { 
 513                 if (code 
!= ResXMLTree::START_TAG
) { 
 517                 String8 
tag(tree
.getElementName(&len
)); 
 518                 //printf("Depth %d tag %s\n", depth, tag.string()); 
 520                     if (tag 
!= "manifest") { 
 521                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 524                     String8 pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 525                     printf("package: %s\n", pkg
.string()); 
 526                 } else if (depth 
== 2 && tag 
== "permission") { 
 528                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 530                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 533                     printf("permission: %s\n", name
.string()); 
 534                 } else if (depth 
== 2 && tag 
== "uses-permission") { 
 536                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 538                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 541                     printf("uses-permission: %s\n", name
.string()); 
 544         } else if (strcmp("badging", option
) == 0) { 
 546             ResXMLTree::event_code_t code
; 
 549             bool withinActivity 
= false; 
 550             bool isMainActivity 
= false; 
 551             bool isLauncherActivity 
= false; 
 552             bool isSearchable 
= false; 
 553             bool withinApplication 
= false; 
 554             bool withinReceiver 
= false; 
 555             bool withinService 
= false; 
 556             bool withinIntentFilter 
= false; 
 557             bool hasMainActivity 
= false; 
 558             bool hasOtherActivities 
= false; 
 559             bool hasOtherReceivers 
= false; 
 560             bool hasOtherServices 
= false; 
 561             bool hasWallpaperService 
= false; 
 562             bool hasImeService 
= false; 
 563             bool hasWidgetReceivers 
= false; 
 564             bool hasIntentFilter 
= false; 
 565             bool actMainActivity 
= false; 
 566             bool actWidgetReceivers 
= false; 
 567             bool actImeService 
= false; 
 568             bool actWallpaperService 
= false; 
 570             // This next group of variables is used to implement a group of 
 571             // backward-compatibility heuristics necessitated by the addition of 
 572             // some new uses-feature constants in 2.1 and 2.2. In most cases, the 
 573             // heuristic is "if an app requests a permission but doesn't explicitly 
 574             // request the corresponding <uses-feature>, presume it's there anyway". 
 575             bool specCameraFeature 
= false; // camera-related 
 576             bool specCameraAutofocusFeature 
= false; 
 577             bool reqCameraAutofocusFeature 
= false; 
 578             bool reqCameraFlashFeature 
= false; 
 579             bool hasCameraPermission 
= false; 
 580             bool specLocationFeature 
= false; // location-related 
 581             bool specNetworkLocFeature 
= false; 
 582             bool reqNetworkLocFeature 
= false; 
 583             bool specGpsFeature 
= false; 
 584             bool reqGpsFeature 
= false; 
 585             bool hasMockLocPermission 
= false; 
 586             bool hasCoarseLocPermission 
= false; 
 587             bool hasGpsPermission 
= false; 
 588             bool hasGeneralLocPermission 
= false; 
 589             bool specBluetoothFeature 
= false; // Bluetooth API-related 
 590             bool hasBluetoothPermission 
= false; 
 591             bool specMicrophoneFeature 
= false; // microphone-related 
 592             bool hasRecordAudioPermission 
= false; 
 593             bool specWiFiFeature 
= false; 
 594             bool hasWiFiPermission 
= false; 
 595             bool specTelephonyFeature 
= false; // telephony-related 
 596             bool reqTelephonySubFeature 
= false; 
 597             bool hasTelephonyPermission 
= false; 
 598             bool specTouchscreenFeature 
= false; // touchscreen-related 
 599             bool specMultitouchFeature 
= false; 
 600             bool reqDistinctMultitouchFeature 
= false; 
 601             // 2.2 also added some other features that apps can request, but that 
 602             // have no corresponding permission, so we cannot implement any 
 603             // back-compatibility heuristic for them. The below are thus unnecessary 
 604             // (but are retained here for documentary purposes.) 
 605             //bool specCompassFeature = false; 
 606             //bool specAccelerometerFeature = false; 
 607             //bool specProximityFeature = false; 
 608             //bool specAmbientLightFeature = false; 
 609             //bool specLiveWallpaperFeature = false; 
 613             int normalScreen 
= 1; 
 615             int xlargeScreen 
= 1; 
 618             String8 activityName
; 
 619             String8 activityLabel
; 
 620             String8 activityIcon
; 
 621             String8 receiverName
; 
 623             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 624                 if (code 
== ResXMLTree::END_TAG
) { 
 627                         withinApplication 
= false; 
 628                     } else if (depth 
< 3) { 
 629                         if (withinActivity 
&& isMainActivity 
&& isLauncherActivity
) { 
 630                             const char *aName 
= getComponentName(pkg
, activityName
); 
 632                                 printf("launchable activity name='%s'", aName
); 
 634                             printf("label='%s' icon='%s'\n", 
 635                                     activityLabel
.string(), 
 636                                     activityIcon
.string()); 
 638                         if (!hasIntentFilter
) { 
 639                             hasOtherActivities 
|= withinActivity
; 
 640                             hasOtherReceivers 
|= withinReceiver
; 
 641                             hasOtherServices 
|= withinService
; 
 643                         withinActivity 
= false; 
 644                         withinService 
= false; 
 645                         withinReceiver 
= false; 
 646                         hasIntentFilter 
= false; 
 647                         isMainActivity 
= isLauncherActivity 
= false; 
 648                     } else if (depth 
< 4) { 
 649                         if (withinIntentFilter
) { 
 650                             if (withinActivity
) { 
 651                                 hasMainActivity 
|= actMainActivity
; 
 652                                 hasOtherActivities 
|= !actMainActivity
; 
 653                             } else if (withinReceiver
) { 
 654                                 hasWidgetReceivers 
|= actWidgetReceivers
; 
 655                                 hasOtherReceivers 
|= !actWidgetReceivers
; 
 656                             } else if (withinService
) { 
 657                                 hasImeService 
|= actImeService
; 
 658                                 hasWallpaperService 
|= actWallpaperService
; 
 659                                 hasOtherServices 
|= (!actImeService 
&& !actWallpaperService
); 
 662                         withinIntentFilter 
= false; 
 666                 if (code 
!= ResXMLTree::START_TAG
) { 
 670                 String8 
tag(tree
.getElementName(&len
)); 
 671                 //printf("Depth %d,  %s\n", depth, tag.string()); 
 673                     if (tag 
!= "manifest") { 
 674                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 677                     pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 678                     printf("package: name='%s' ", pkg
.string()); 
 679                     int32_t versionCode 
= getIntegerAttribute(tree
, VERSION_CODE_ATTR
, &error
); 
 681                         fprintf(stderr
, "ERROR getting 'android:versionCode' attribute: %s\n", error
.string()); 
 684                     if (versionCode 
> 0) { 
 685                         printf("versionCode='%d' ", versionCode
); 
 687                         printf("versionCode='' "); 
 689                     String8 versionName 
= getResolvedAttribute(&res
, tree
, VERSION_NAME_ATTR
, &error
); 
 691                         fprintf(stderr
, "ERROR getting 'android:versionName' attribute: %s\n", error
.string()); 
 694                     printf("versionName='%s'\n", versionName
.string()); 
 695                 } else if (depth 
== 2) { 
 696                     withinApplication 
= false; 
 697                     if (tag 
== "application") { 
 698                         withinApplication 
= true; 
 699                         String8 label 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 701                              fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
 704                         printf("application: label='%s' ", label
.string()); 
 705                         String8 icon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 707                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 710                         printf("icon='%s'\n", icon
.string()); 
 711                         int32_t testOnly 
= getIntegerAttribute(tree
, TEST_ONLY_ATTR
, &error
, 0); 
 713                             fprintf(stderr
, "ERROR getting 'android:testOnly' attribute: %s\n", error
.string()); 
 717                             printf("testOnly='%d'\n", testOnly
); 
 719                     } else if (tag 
== "uses-sdk") { 
 720                         int32_t code 
= getIntegerAttribute(tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 723                             String8 name 
= getResolvedAttribute(&res
, tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 725                                 fprintf(stderr
, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 
 729                             if (name 
== "Donut") targetSdk 
= 4; 
 730                             printf("sdkVersion:'%s'\n", name
.string()); 
 731                         } else if (code 
!= -1) { 
 733                             printf("sdkVersion:'%d'\n", code
); 
 735                         code 
= getIntegerAttribute(tree
, MAX_SDK_VERSION_ATTR
, NULL
, -1); 
 737                             printf("maxSdkVersion:'%d'\n", code
); 
 739                         code 
= getIntegerAttribute(tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 742                             String8 name 
= getResolvedAttribute(&res
, tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 744                                 fprintf(stderr
, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 
 748                             if (name 
== "Donut" && targetSdk 
< 4) targetSdk 
= 4; 
 749                             printf("targetSdkVersion:'%s'\n", name
.string()); 
 750                         } else if (code 
!= -1) { 
 751                             if (targetSdk 
< code
) { 
 754                             printf("targetSdkVersion:'%d'\n", code
); 
 756                     } else if (tag 
== "uses-configuration") { 
 757                         int32_t reqTouchScreen 
= getIntegerAttribute(tree
, 
 758                                 REQ_TOUCH_SCREEN_ATTR
, NULL
, 0); 
 759                         int32_t reqKeyboardType 
= getIntegerAttribute(tree
, 
 760                                 REQ_KEYBOARD_TYPE_ATTR
, NULL
, 0); 
 761                         int32_t reqHardKeyboard 
= getIntegerAttribute(tree
, 
 762                                 REQ_HARD_KEYBOARD_ATTR
, NULL
, 0); 
 763                         int32_t reqNavigation 
= getIntegerAttribute(tree
, 
 764                                 REQ_NAVIGATION_ATTR
, NULL
, 0); 
 765                         int32_t reqFiveWayNav 
= getIntegerAttribute(tree
, 
 766                                 REQ_FIVE_WAY_NAV_ATTR
, NULL
, 0); 
 767                         printf("uses-configuration:"); 
 768                         if (reqTouchScreen 
!= 0) { 
 769                             printf(" reqTouchScreen='%d'", reqTouchScreen
); 
 771                         if (reqKeyboardType 
!= 0) { 
 772                             printf(" reqKeyboardType='%d'", reqKeyboardType
); 
 774                         if (reqHardKeyboard 
!= 0) { 
 775                             printf(" reqHardKeyboard='%d'", reqHardKeyboard
); 
 777                         if (reqNavigation 
!= 0) { 
 778                             printf(" reqNavigation='%d'", reqNavigation
); 
 780                         if (reqFiveWayNav 
!= 0) { 
 781                             printf(" reqFiveWayNav='%d'", reqFiveWayNav
); 
 784                     } else if (tag 
== "supports-screens") { 
 785                         smallScreen 
= getIntegerAttribute(tree
, 
 786                                 SMALL_SCREEN_ATTR
, NULL
, 1); 
 787                         normalScreen 
= getIntegerAttribute(tree
, 
 788                                 NORMAL_SCREEN_ATTR
, NULL
, 1); 
 789                         largeScreen 
= getIntegerAttribute(tree
, 
 790                                 LARGE_SCREEN_ATTR
, NULL
, 1); 
 791                         xlargeScreen 
= getIntegerAttribute(tree
, 
 792                                 XLARGE_SCREEN_ATTR
, NULL
, 1); 
 793                         anyDensity 
= getIntegerAttribute(tree
, 
 794                                 ANY_DENSITY_ATTR
, NULL
, 1); 
 795                     } else if (tag 
== "uses-feature") { 
 796                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 798                         if (name 
!= "" && error 
== "") { 
 799                             int req 
= getIntegerAttribute(tree
, 
 800                                     REQUIRED_ATTR
, NULL
, 1); 
 802                             if (name 
== "android.hardware.camera") { 
 803                                 specCameraFeature 
= true; 
 804                             } else if (name 
== "android.hardware.camera.autofocus") { 
 805                                 // these have no corresponding permission to check for, 
 806                                 // but should imply the foundational camera permission 
 807                                 reqCameraAutofocusFeature 
= reqCameraAutofocusFeature 
|| req
; 
 808                                 specCameraAutofocusFeature 
= true; 
 809                             } else if (req 
&& (name 
== "android.hardware.camera.flash")) { 
 810                                 // these have no corresponding permission to check for, 
 811                                 // but should imply the foundational camera permission 
 812                                 reqCameraFlashFeature 
= true; 
 813                             } else if (name 
== "android.hardware.location") { 
 814                                 specLocationFeature 
= true; 
 815                             } else if (name 
== "android.hardware.location.network") { 
 816                                 specNetworkLocFeature 
= true; 
 817                                 reqNetworkLocFeature 
= reqNetworkLocFeature 
|| req
; 
 818                             } else if (name 
== "android.hardware.location.gps") { 
 819                                 specGpsFeature 
= true; 
 820                                 reqGpsFeature 
= reqGpsFeature 
|| req
; 
 821                             } else if (name 
== "android.hardware.bluetooth") { 
 822                                 specBluetoothFeature 
= true; 
 823                             } else if (name 
== "android.hardware.touchscreen") { 
 824                                 specTouchscreenFeature 
= true; 
 825                             } else if (name 
== "android.hardware.touchscreen.multitouch") { 
 826                                 specMultitouchFeature 
= true; 
 827                             } else if (name 
== "android.hardware.touchscreen.multitouch.distinct") { 
 828                                 reqDistinctMultitouchFeature 
= reqDistinctMultitouchFeature 
|| req
; 
 829                             } else if (name 
== "android.hardware.microphone") { 
 830                                 specMicrophoneFeature 
= true; 
 831                             } else if (name 
== "android.hardware.wifi") { 
 832                                 specWiFiFeature 
= true; 
 833                             } else if (name 
== "android.hardware.telephony") { 
 834                                 specTelephonyFeature 
= true; 
 835                             } else if (req 
&& (name 
== "android.hardware.telephony.gsm" || 
 836                                                name 
== "android.hardware.telephony.cdma")) { 
 837                                 // these have no corresponding permission to check for, 
 838                                 // but should imply the foundational telephony permission 
 839                                 reqTelephonySubFeature 
= true; 
 841                             printf("uses-feature%s:'%s'\n", 
 842                                     req 
? "" : "-not-required", name
.string()); 
 844                             int vers 
= getIntegerAttribute(tree
, 
 845                                     GL_ES_VERSION_ATTR
, &error
); 
 847                                 printf("uses-gl-es:'0x%x'\n", vers
); 
 850                     } else if (tag 
== "uses-permission") { 
 851                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 852                         if (name 
!= "" && error 
== "") { 
 853                             if (name 
== "android.permission.CAMERA") { 
 854                                 hasCameraPermission 
= true; 
 855                             } else if (name 
== "android.permission.ACCESS_FINE_LOCATION") { 
 856                                 hasGpsPermission 
= true; 
 857                             } else if (name 
== "android.permission.ACCESS_MOCK_LOCATION") { 
 858                                 hasMockLocPermission 
= true; 
 859                             } else if (name 
== "android.permission.ACCESS_COARSE_LOCATION") { 
 860                                 hasCoarseLocPermission 
= true; 
 861                             } else if (name 
== "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" || 
 862                                        name 
== "android.permission.INSTALL_LOCATION_PROVIDER") { 
 863                                 hasGeneralLocPermission 
= true; 
 864                             } else if (name 
== "android.permission.BLUETOOTH" || 
 865                                        name 
== "android.permission.BLUETOOTH_ADMIN") { 
 866                                 hasBluetoothPermission 
= true; 
 867                             } else if (name 
== "android.permission.RECORD_AUDIO") { 
 868                                 hasRecordAudioPermission 
= true; 
 869                             } else if (name 
== "android.permission.ACCESS_WIFI_STATE" || 
 870                                        name 
== "android.permission.CHANGE_WIFI_STATE" || 
 871                                        name 
== "android.permission.CHANGE_WIFI_MULTICAST_STATE") { 
 872                                 hasWiFiPermission 
= true; 
 873                             } else if (name 
== "android.permission.CALL_PHONE" || 
 874                                        name 
== "android.permission.CALL_PRIVILEGED" || 
 875                                        name 
== "android.permission.MODIFY_PHONE_STATE" || 
 876                                        name 
== "android.permission.PROCESS_OUTGOING_CALLS" || 
 877                                        name 
== "android.permission.READ_SMS" || 
 878                                        name 
== "android.permission.RECEIVE_SMS" || 
 879                                        name 
== "android.permission.RECEIVE_MMS" || 
 880                                        name 
== "android.permission.RECEIVE_WAP_PUSH" || 
 881                                        name 
== "android.permission.SEND_SMS" || 
 882                                        name 
== "android.permission.WRITE_APN_SETTINGS" || 
 883                                        name 
== "android.permission.WRITE_SMS") { 
 884                                 hasTelephonyPermission 
= true; 
 886                             printf("uses-permission:'%s'\n", name
.string()); 
 888                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
 892                     } else if (tag 
== "uses-package") { 
 893                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 894                         if (name 
!= "" && error 
== "") { 
 895                             printf("uses-package:'%s'\n", name
.string()); 
 897                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
 901                     } else if (tag 
== "original-package") { 
 902                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 903                         if (name 
!= "" && error 
== "") { 
 904                             printf("original-package:'%s'\n", name
.string()); 
 906                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
 910                     } else if (tag 
== "supports-gl-texture") { 
 911                         String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 912                         if (name 
!= "" && error 
== "") { 
 913                             printf("supports-gl-texture:'%s'\n", name
.string()); 
 915                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", 
 919                     } else if (tag 
== "compatible-screens") { 
 920                         printCompatibleScreens(tree
); 
 923                 } else if (depth 
== 3 && withinApplication
) { 
 924                     withinActivity 
= false; 
 925                     withinReceiver 
= false; 
 926                     withinService 
= false; 
 927                     hasIntentFilter 
= false; 
 928                     if(tag 
== "activity") { 
 929                         withinActivity 
= true; 
 930                         activityName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 932                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
 936                         activityLabel 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 938                             fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
 942                         activityIcon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 944                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 947                     } else if (tag 
== "uses-library") { 
 948                         String8 libraryName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 950                             fprintf(stderr
, "ERROR getting 'android:name' attribute for uses-library: %s\n", error
.string()); 
 953                         int req 
= getIntegerAttribute(tree
, 
 954                                 REQUIRED_ATTR
, NULL
, 1); 
 955                         printf("uses-library%s:'%s'\n", 
 956                                 req 
? "" : "-not-required", libraryName
.string()); 
 957                     } else if (tag 
== "receiver") { 
 958                         withinReceiver 
= true; 
 959                         receiverName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 962                             fprintf(stderr
, "ERROR getting 'android:name' attribute for receiver: %s\n", error
.string()); 
 965                     } else if (tag 
== "service") { 
 966                         withinService 
= true; 
 967                         serviceName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 970                             fprintf(stderr
, "ERROR getting 'android:name' attribute for service: %s\n", error
.string()); 
 974                 } else if ((depth 
== 4) && (tag 
== "intent-filter")) { 
 975                     hasIntentFilter 
= true; 
 976                     withinIntentFilter 
= true; 
 977                     actMainActivity 
= actWidgetReceivers 
= actImeService 
= actWallpaperService 
= false; 
 978                 } else if ((depth 
== 5) && withinIntentFilter
){ 
 980                     if (tag 
== "action") { 
 981                         action 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 983                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
 986                         if (withinActivity
) { 
 987                             if (action 
== "android.intent.action.MAIN") { 
 988                                 isMainActivity 
= true; 
 989                                 actMainActivity 
= true; 
 991                         } else if (withinReceiver
) { 
 992                             if (action 
== "android.appwidget.action.APPWIDGET_UPDATE") { 
 993                                 actWidgetReceivers 
= true; 
 995                         } else if (withinService
) { 
 996                             if (action 
== "android.view.InputMethod") { 
 997                                 actImeService 
= true; 
 998                             } else if (action 
== "android.service.wallpaper.WallpaperService") { 
 999                                 actWallpaperService 
= true; 
1002                         if (action 
== "android.intent.action.SEARCH") { 
1003                             isSearchable 
= true; 
1007                     if (tag 
== "category") { 
1008                         String8 category 
= getAttribute(tree
, NAME_ATTR
, &error
); 
1010                             fprintf(stderr
, "ERROR getting 'name' attribute: %s\n", error
.string()); 
1013                         if (withinActivity
) { 
1014                             if (category 
== "android.intent.category.LAUNCHER") { 
1015                                 isLauncherActivity 
= true; 
1022             /* The following blocks handle printing "inferred" uses-features, based 
1023              * on whether related features or permissions are used by the app. 
1024              * Note that the various spec*Feature variables denote whether the 
1025              * relevant tag was *present* in the AndroidManfest, not that it was 
1026              * present and set to true. 
1028             // Camera-related back-compatibility logic 
1029             if (!specCameraFeature
) { 
1030                 if (reqCameraFlashFeature 
|| reqCameraAutofocusFeature
) { 
1031                     // if app requested a sub-feature (autofocus or flash) and didn't 
1032                     // request the base camera feature, we infer that it meant to 
1033                     printf("uses-feature:'android.hardware.camera'\n"); 
1034                 } else if (hasCameraPermission
) { 
1035                     // if app wants to use camera but didn't request the feature, we infer  
1036                     // that it meant to, and further that it wants autofocus 
1037                     // (which was the 1.0 - 1.5 behavior) 
1038                     printf("uses-feature:'android.hardware.camera'\n"); 
1039                     if (!specCameraAutofocusFeature
) { 
1040                         printf("uses-feature:'android.hardware.camera.autofocus'\n"); 
1045             // Location-related back-compatibility logic 
1046             if (!specLocationFeature 
&& 
1047                 (hasMockLocPermission 
|| hasCoarseLocPermission 
|| hasGpsPermission 
|| 
1048                  hasGeneralLocPermission 
|| reqNetworkLocFeature 
|| reqGpsFeature
)) { 
1049                 // if app either takes a location-related permission or requests one of the 
1050                 // sub-features, we infer that it also meant to request the base location feature 
1051                 printf("uses-feature:'android.hardware.location'\n"); 
1053             if (!specGpsFeature 
&& hasGpsPermission
) { 
1054                 // if app takes GPS (FINE location) perm but does not request the GPS 
1055                 // feature, we infer that it meant to 
1056                 printf("uses-feature:'android.hardware.location.gps'\n"); 
1058             if (!specNetworkLocFeature 
&& hasCoarseLocPermission
) { 
1059                 // if app takes Network location (COARSE location) perm but does not request the 
1060                 // network location feature, we infer that it meant to 
1061                 printf("uses-feature:'android.hardware.location.network'\n"); 
1064             // Bluetooth-related compatibility logic 
1065             if (!specBluetoothFeature 
&& hasBluetoothPermission 
&& (targetSdk 
> 4)) { 
1066                 // if app takes a Bluetooth permission but does not request the Bluetooth 
1067                 // feature, we infer that it meant to 
1068                 printf("uses-feature:'android.hardware.bluetooth'\n"); 
1071             // Microphone-related compatibility logic 
1072             if (!specMicrophoneFeature 
&& hasRecordAudioPermission
) { 
1073                 // if app takes the record-audio permission but does not request the microphone 
1074                 // feature, we infer that it meant to 
1075                 printf("uses-feature:'android.hardware.microphone'\n"); 
1078             // WiFi-related compatibility logic 
1079             if (!specWiFiFeature 
&& hasWiFiPermission
) { 
1080                 // if app takes one of the WiFi permissions but does not request the WiFi 
1081                 // feature, we infer that it meant to 
1082                 printf("uses-feature:'android.hardware.wifi'\n"); 
1085             // Telephony-related compatibility logic 
1086             if (!specTelephonyFeature 
&& (hasTelephonyPermission 
|| reqTelephonySubFeature
)) { 
1087                 // if app takes one of the telephony permissions or requests a sub-feature but 
1088                 // does not request the base telephony feature, we infer that it meant to 
1089                 printf("uses-feature:'android.hardware.telephony'\n"); 
1092             // Touchscreen-related back-compatibility logic 
1093             if (!specTouchscreenFeature
) { // not a typo! 
1094                 // all apps are presumed to require a touchscreen, unless they explicitly say 
1095                 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> 
1096                 // Note that specTouchscreenFeature is true if the tag is present, regardless 
1097                 // of whether its value is true or false, so this is safe 
1098                 printf("uses-feature:'android.hardware.touchscreen'\n"); 
1100             if (!specMultitouchFeature 
&& reqDistinctMultitouchFeature
) { 
1101                 // if app takes one of the telephony permissions or requests a sub-feature but 
1102                 // does not request the base telephony feature, we infer that it meant to 
1103                 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n"); 
1106             if (hasMainActivity
) { 
1109             if (hasWidgetReceivers
) { 
1110                 printf("app-widget\n"); 
1112             if (hasImeService
) { 
1115             if (hasWallpaperService
) { 
1116                 printf("wallpaper\n"); 
1118             if (hasOtherActivities
) { 
1119                 printf("other-activities\n"); 
1124             if (hasOtherReceivers
) { 
1125                 printf("other-receivers\n"); 
1127             if (hasOtherServices
) { 
1128                 printf("other-services\n"); 
1131             // Determine default values for any unspecified screen sizes, 
1132             // based on the target SDK of the package.  As of 4 (donut) 
1133             // the screen size support was introduced, so all default to 
1135             if (smallScreen 
> 0) { 
1136                 smallScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1138             if (normalScreen 
> 0) { 
1141             if (largeScreen 
> 0) { 
1142                 largeScreen 
= targetSdk 
>= 4 ? -1 : 0; 
1144             if (xlargeScreen 
> 0) { 
1145                 // Introduced in Gingerbread. 
1146                 xlargeScreen 
= targetSdk 
>= 9 ? -1 : 0; 
1148             if (anyDensity 
> 0) { 
1149                 anyDensity 
= targetSdk 
>= 4 ? -1 : 0; 
1151             printf("supports-screens:"); 
1152             if (smallScreen 
!= 0) printf(" 'small'"); 
1153             if (normalScreen 
!= 0) printf(" 'normal'"); 
1154             if (largeScreen 
!= 0) printf(" 'large'"); 
1155             if (xlargeScreen 
!= 0) printf(" 'xlarge'"); 
1158             printf("supports-any-density: '%s'\n", anyDensity 
? "true" : "false"); 
1161             Vector
<String8
> locales
; 
1162             res
.getLocales(&locales
); 
1163             const size_t NL 
= locales
.size(); 
1164             for (size_t i
=0; i
<NL
; i
++) { 
1165                 const char* localeStr 
=  locales
[i
].string(); 
1166                 if (localeStr 
== NULL 
|| strlen(localeStr
) == 0) { 
1167                     localeStr 
= "--_--"; 
1169                 printf(" '%s'", localeStr
); 
1173             Vector
<ResTable_config
> configs
; 
1174             res
.getConfigurations(&configs
); 
1175             SortedVector
<int> densities
; 
1176             const size_t NC 
= configs
.size(); 
1177             for (size_t i
=0; i
<NC
; i
++) { 
1178                 int dens 
= configs
[i
].density
; 
1179                 if (dens 
== 0) dens 
= 160; 
1180                 densities
.add(dens
); 
1183             printf("densities:"); 
1184             const size_t ND 
= densities
.size(); 
1185             for (size_t i
=0; i
<ND
; i
++) { 
1186                 printf(" '%d'", densities
[i
]); 
1190             AssetDir
* dir 
= assets
.openNonAssetDir(assetsCookie
, "lib"); 
1192                 if (dir
->getFileCount() > 0) { 
1193                     printf("native-code:"); 
1194                     for (size_t i
=0; i
<dir
->getFileCount(); i
++) { 
1195                         printf(" '%s'", dir
->getFileName(i
).string()); 
1201         } else if (strcmp("configurations", option
) == 0) { 
1202             Vector
<ResTable_config
> configs
; 
1203             res
.getConfigurations(&configs
); 
1204             const size_t N 
= configs
.size(); 
1205             for (size_t i
=0; i
<N
; i
++) { 
1206                 printf("%s\n", configs
[i
].toString().string()); 
1209             fprintf(stderr
, "ERROR: unknown dump option '%s'\n", option
); 
1220     return (result 
!= NO_ERROR
); 
1225  * Handle the "add" command, which wants to add files to a new or 
1226  * pre-existing archive. 
1228 int doAdd(Bundle
* bundle
) 
1230     ZipFile
* zip 
= NULL
; 
1231     status_t result 
= UNKNOWN_ERROR
; 
1232     const char* zipFileName
; 
1234     if (bundle
->getUpdate()) { 
1235         /* avoid confusion */ 
1236         fprintf(stderr
, "ERROR: can't use '-u' with add\n"); 
1240     if (bundle
->getFileSpecCount() < 1) { 
1241         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1244     zipFileName 
= bundle
->getFileSpecEntry(0); 
1246     if (bundle
->getFileSpecCount() < 2) { 
1247         fprintf(stderr
, "NOTE: nothing to do\n"); 
1251     zip 
= openReadWrite(zipFileName
, true); 
1253         fprintf(stderr
, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName
); 
1257     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1258         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1260         if (strcasecmp(String8(fileName
).getPathExtension().string(), ".gz") == 0) { 
1261             printf(" '%s'... (from gzip)\n", fileName
); 
1262             result 
= zip
->addGzip(fileName
, String8(fileName
).getBasePath().string(), NULL
); 
1264             if (bundle
->getJunkPath()) { 
1265                 String8 storageName 
= String8(fileName
).getPathLeaf(); 
1266                 printf(" '%s' as '%s'...\n", fileName
, storageName
.string()); 
1267                 result 
= zip
->add(fileName
, storageName
.string(), 
1268                                   bundle
->getCompressionMethod(), NULL
); 
1270                 printf(" '%s'...\n", fileName
); 
1271                 result 
= zip
->add(fileName
, bundle
->getCompressionMethod(), NULL
); 
1274         if (result 
!= NO_ERROR
) { 
1275             fprintf(stderr
, "Unable to add '%s' to '%s'", bundle
->getFileSpecEntry(i
), zipFileName
); 
1276             if (result 
== NAME_NOT_FOUND
) 
1277                 fprintf(stderr
, ": file not found\n"); 
1278             else if (result 
== ALREADY_EXISTS
) 
1279                 fprintf(stderr
, ": already exists in archive\n"); 
1281                 fprintf(stderr
, "\n"); 
1290     return (result 
!= NO_ERROR
); 
1295  * Delete files from an existing archive. 
1297 int doRemove(Bundle
* bundle
) 
1299     ZipFile
* zip 
= NULL
; 
1300     status_t result 
= UNKNOWN_ERROR
; 
1301     const char* zipFileName
; 
1303     if (bundle
->getFileSpecCount() < 1) { 
1304         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
1307     zipFileName 
= bundle
->getFileSpecEntry(0); 
1309     if (bundle
->getFileSpecCount() < 2) { 
1310         fprintf(stderr
, "NOTE: nothing to do\n"); 
1314     zip 
= openReadWrite(zipFileName
, false); 
1316         fprintf(stderr
, "ERROR: failed opening Zip archive '%s'\n", 
1321     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
1322         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
1325         entry 
= zip
->getEntryByName(fileName
); 
1326         if (entry 
== NULL
) { 
1327             printf(" '%s' NOT FOUND\n", fileName
); 
1331         result 
= zip
->remove(entry
); 
1333         if (result 
!= NO_ERROR
) { 
1334             fprintf(stderr
, "Unable to delete '%s' from '%s'\n", 
1335                 bundle
->getFileSpecEntry(i
), zipFileName
); 
1340     /* update the archive */ 
1345     return (result 
!= NO_ERROR
); 
1350  * Package up an asset directory and associated application files. 
1352 int doPackage(Bundle
* bundle
) 
1354     const char* outputAPKFile
; 
1357     sp
<AaptAssets
> assets
; 
1360     // -c zz_ZZ means do pseudolocalization 
1361     ResourceFilter filter
; 
1362     err 
= filter
.parse(bundle
->getConfigurations()); 
1363     if (err 
!= NO_ERROR
) { 
1366     if (filter
.containsPseudo()) { 
1367         bundle
->setPseudolocalize(true); 
1370     N 
= bundle
->getFileSpecCount(); 
1371     if (N 
< 1 && bundle
->getResourceSourceDirs().size() == 0 && bundle
->getJarFiles().size() == 0 
1372             && bundle
->getAndroidManifestFile() == NULL 
&& bundle
->getAssetSourceDir() == NULL
) { 
1373         fprintf(stderr
, "ERROR: no input files\n"); 
1377     outputAPKFile 
= bundle
->getOutputAPKFile(); 
1379     // Make sure the filenames provided exist and are of the appropriate type. 
1380     if (outputAPKFile
) { 
1382         type 
= getFileType(outputAPKFile
); 
1383         if (type 
!= kFileTypeNonexistent 
&& type 
!= kFileTypeRegular
) { 
1385                 "ERROR: output file '%s' exists but is not regular file\n", 
1392     assets 
= new AaptAssets(); 
1393     err 
= assets
->slurpFromArgs(bundle
); 
1398     if (bundle
->getVerbose()) { 
1402     // If they asked for any files that need to be compiled, do so. 
1403     if (bundle
->getResourceSourceDirs().size() || bundle
->getAndroidManifestFile()) { 
1404         err 
= buildResources(bundle
, assets
); 
1410     // At this point we've read everything and processed everything.  From here 
1411     // on out it's just writing output files. 
1412     if (SourcePos::hasErrors()) { 
1416     // Write out R.java constants 
1417     if (assets
->getPackage() == assets
->getSymbolsPrivatePackage()) { 
1418         if (bundle
->getCustomPackage() == NULL
) { 
1419             err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), true); 
1421             const String8 
customPkg(bundle
->getCustomPackage()); 
1422             err 
= writeResourceSymbols(bundle
, assets
, customPkg
, true); 
1428         err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), false); 
1432         err 
= writeResourceSymbols(bundle
, assets
, assets
->getSymbolsPrivatePackage(), true); 
1438     // Write out the ProGuard file 
1439     err 
= writeProguardFile(bundle
, assets
); 
1445     if (outputAPKFile
) { 
1446         err 
= writeAPK(bundle
, assets
, String8(outputAPKFile
)); 
1447         if (err 
!= NO_ERROR
) { 
1448             fprintf(stderr
, "ERROR: packaging of '%s' failed\n", outputAPKFile
); 
1455     if (SourcePos::hasErrors()) { 
1456         SourcePos::printErrors(stderr
);