]>
git.saurik.com Git - android/aapt.git/blob - Command.cpp
32df6317e2884973ab362e230d54e4b779c3ed23
   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> 
  15 #include <utils/ZipFile.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   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%%  %s  %08lx  %s\n", 
 164                 (long) entry
->getUncompressedLen(), 
 165                 compressionName(entry
->getCompressionMethod()), 
 166                 (long) entry
->getCompressedLen(), 
 167                 calcPercent(entry
->getUncompressedLen(), 
 168                             entry
->getCompressedLen()), 
 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             printf("\nResource table:\n"); 
 205         Asset
* manifestAsset 
= assets
.openNonAsset("AndroidManifest.xml", 
 206                                                    Asset::ACCESS_BUFFER
); 
 207         if (manifestAsset 
== NULL
) { 
 208             printf("\nNo AndroidManifest.xml found.\n"); 
 210             printf("\nAndroid manifest:\n"); 
 212             tree
.setTo(manifestAsset
->getBuffer(true), 
 213                        manifestAsset
->getLength()); 
 214             printXMLBlock(&tree
); 
 216         delete manifestAsset
; 
 226 static ssize_t 
indexOfAttribute(const ResXMLTree
& tree
, uint32_t attrRes
) 
 228     size_t N 
= tree
.getAttributeCount(); 
 229     for (size_t i
=0; i
<N
; i
++) { 
 230         if (tree
.getAttributeNameResID(i
) == attrRes
) { 
 237 static String8 
getAttribute(const ResXMLTree
& tree
, const char* ns
, 
 238                             const char* attr
, String8
* outError
) 
 240     ssize_t idx 
= tree
.indexOfAttribute(ns
, attr
); 
 245     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 246         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 247             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 252     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 253     return str 
? String8(str
, len
) : String8(); 
 256 static String8 
getAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, String8
* outError
) 
 258     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 263     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 264         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 265             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 270     const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 271     return str 
? String8(str
, len
) : String8(); 
 274 static int32_t getIntegerAttribute(const ResXMLTree
& tree
, uint32_t attrRes
, 
 275         String8
* outError
, int32_t defValue 
= -1) 
 277     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 282     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 283         if (value
.dataType 
< Res_value::TYPE_FIRST_INT
 
 284                 || value
.dataType 
> Res_value::TYPE_LAST_INT
) { 
 285             if (outError 
!= NULL
) *outError 
= "attribute is not an integer value"; 
 292 static String8 
getResolvedAttribute(const ResTable
* resTable
, const ResXMLTree
& tree
, 
 293         uint32_t attrRes
, String8
* outError
) 
 295     ssize_t idx 
= indexOfAttribute(tree
, attrRes
); 
 300     if (tree
.getAttributeValue(idx
, &value
) != NO_ERROR
) { 
 301         if (value
.dataType 
== Res_value::TYPE_STRING
) { 
 303             const uint16_t* str 
= tree
.getAttributeStringValue(idx
, &len
); 
 304             return str 
? String8(str
, len
) : String8(); 
 306         resTable
->resolveReference(&value
, 0); 
 307         if (value
.dataType 
!= Res_value::TYPE_STRING
) { 
 308             if (outError 
!= NULL
) *outError 
= "attribute is not a string value"; 
 313     const Res_value
* value2 
= &value
; 
 314     const char16_t* str 
= const_cast<ResTable
*>(resTable
)->valueToString(value2
, 0, NULL
, &len
); 
 315     return str 
? String8(str
, len
) : String8(); 
 318 // These are attribute resource constants for the platform, as found 
 321     NAME_ATTR 
= 0x01010003, 
 322     VERSION_CODE_ATTR 
= 0x0101021b, 
 323     VERSION_NAME_ATTR 
= 0x0101021c, 
 324     LABEL_ATTR 
= 0x01010001, 
 325     ICON_ATTR 
= 0x01010002, 
 326     MIN_SDK_VERSION_ATTR 
= 0x0101020c, 
 327     REQ_TOUCH_SCREEN_ATTR 
= 0x01010227, 
 328     REQ_KEYBOARD_TYPE_ATTR 
= 0x01010228, 
 329     REQ_HARD_KEYBOARD_ATTR 
= 0x01010229, 
 330     REQ_NAVIGATION_ATTR 
= 0x0101022a, 
 331     REQ_FIVE_WAY_NAV_ATTR 
= 0x01010232, 
 332     TARGET_SDK_VERSION_ATTR 
= 0x01010270, 
 333     TEST_ONLY_ATTR 
= 0x01010272, 
 334     DENSITY_ATTR 
= 0x0101026c, 
 337 const char *getComponentName(String8 
&pkgName
, String8 
&componentName
) { 
 338     ssize_t idx 
= componentName
.find("."); 
 339     String8 
retStr(pkgName
); 
 341         retStr 
+= componentName
; 
 342     } else if (idx 
< 0) { 
 344         retStr 
+= componentName
; 
 346         return componentName
.string(); 
 348     return retStr
.string(); 
 352  * Handle the "dump" command, to extract select data from an archive. 
 354 int doDump(Bundle
* bundle
) 
 356     status_t result 
= UNKNOWN_ERROR
; 
 359     if (bundle
->getFileSpecCount() < 1) { 
 360         fprintf(stderr
, "ERROR: no dump option specified\n"); 
 364     if (bundle
->getFileSpecCount() < 2) { 
 365         fprintf(stderr
, "ERROR: no dump file specified\n"); 
 369     const char* option 
= bundle
->getFileSpecEntry(0); 
 370     const char* filename 
= bundle
->getFileSpecEntry(1); 
 374     if (!assets
.addAssetPath(String8(filename
), &assetsCookie
)) { 
 375         fprintf(stderr
, "ERROR: dump failed because assets could not be loaded\n"); 
 379     const ResTable
& res 
= assets
.getResources(false); 
 381         fprintf(stderr
, "ERROR: dump failed because no resource table was found\n"); 
 385     if (strcmp("resources", option
) == 0) { 
 388     } else if (strcmp("xmltree", option
) == 0) { 
 389         if (bundle
->getFileSpecCount() < 3) { 
 390             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 394         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 395             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 397             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 399                 fprintf(stderr
, "ERROR: dump failed because resource %p found\n", resname
); 
 403             if (tree
.setTo(asset
->getBuffer(true), 
 404                            asset
->getLength()) != NO_ERROR
) { 
 405                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 409             printXMLBlock(&tree
); 
 414     } else if (strcmp("xmlstrings", option
) == 0) { 
 415         if (bundle
->getFileSpecCount() < 3) { 
 416             fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n"); 
 420         for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) { 
 421             const char* resname 
= bundle
->getFileSpecEntry(i
); 
 423             asset 
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
); 
 425                 fprintf(stderr
, "ERROR: dump failed because resource %p found\n", resname
); 
 429             if (tree
.setTo(asset
->getBuffer(true), 
 430                            asset
->getLength()) != NO_ERROR
) { 
 431                 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
); 
 434             printStringPool(&tree
.getStrings()); 
 441         asset 
= assets
.openNonAsset("AndroidManifest.xml", 
 442                                             Asset::ACCESS_BUFFER
); 
 444             fprintf(stderr
, "ERROR: dump failed because no AndroidManifest.xml found\n"); 
 448         if (tree
.setTo(asset
->getBuffer(true), 
 449                        asset
->getLength()) != NO_ERROR
) { 
 450             fprintf(stderr
, "ERROR: AndroidManifest.xml is corrupt\n"); 
 455         if (strcmp("permissions", option
) == 0) { 
 457             ResXMLTree::event_code_t code
; 
 459             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 460                 if (code 
== ResXMLTree::END_TAG
) { 
 464                 if (code 
!= ResXMLTree::START_TAG
) { 
 468                 String8 
tag(tree
.getElementName(&len
)); 
 469                 //printf("Depth %d tag %s\n", depth, tag.string()); 
 471                     if (tag 
!= "manifest") { 
 472                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 475                     String8 pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 476                     printf("package: %s\n", pkg
.string()); 
 477                 } else if (depth 
== 2 && tag 
== "permission") { 
 479                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 481                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 484                     printf("permission: %s\n", name
.string()); 
 485                 } else if (depth 
== 2 && tag 
== "uses-permission") { 
 487                     String8 name 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 489                         fprintf(stderr
, "ERROR: %s\n", error
.string()); 
 492                     printf("uses-permission: %s\n", name
.string()); 
 495         } else if (strcmp("badging", option
) == 0) { 
 497             ResXMLTree::event_code_t code
; 
 500             bool withinActivity 
= false; 
 501             bool isMainActivity 
= false; 
 502             bool isLauncherActivity 
= false; 
 503             bool withinApplication 
= false; 
 504             bool withinReceiver 
= false; 
 506             String8 activityName
; 
 507             String8 activityLabel
; 
 508             String8 activityIcon
; 
 509             String8 receiverName
; 
 510             while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT 
&& code 
!= ResXMLTree::BAD_DOCUMENT
) { 
 511                 if (code 
== ResXMLTree::END_TAG
) { 
 515                 if (code 
!= ResXMLTree::START_TAG
) { 
 519                 String8 
tag(tree
.getElementName(&len
)); 
 520                 //printf("Depth %d tag %s\n", depth, tag.string()); 
 522                     if (tag 
!= "manifest") { 
 523                         fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n"); 
 526                     pkg 
= getAttribute(tree
, NULL
, "package", NULL
); 
 527                     printf("package: name='%s' ", pkg
.string()); 
 528                     int32_t versionCode 
= getIntegerAttribute(tree
, VERSION_CODE_ATTR
, &error
); 
 530                         fprintf(stderr
, "ERROR getting 'android:versionCode' attribute: %s\n", error
.string()); 
 533                     if (versionCode 
> 0) { 
 534                         printf("versionCode='%d' ", versionCode
); 
 536                         printf("versionCode='' "); 
 538                     String8 versionName 
= getAttribute(tree
, VERSION_NAME_ATTR
, &error
); 
 540                         fprintf(stderr
, "ERROR getting 'android:versionName' attribute: %s\n", error
.string()); 
 543                     printf("versionName='%s'\n", versionName
.string()); 
 544                 } else if (depth 
== 2) { 
 545                     withinApplication 
= false; 
 546                     if (tag 
== "application") { 
 547                         withinApplication 
= true; 
 548                         String8 label 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 550                              fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
 553                         printf("application: label='%s' ", label
.string()); 
 554                         String8 icon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 556                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 559                         printf("icon='%s'\n", icon
.string()); 
 560                         int32_t testOnly 
= getIntegerAttribute(tree
, TEST_ONLY_ATTR
, &error
, 0); 
 562                             fprintf(stderr
, "ERROR getting 'android:testOnly' attribute: %s\n", error
.string()); 
 566                             printf("testOnly='%d'\n", testOnly
); 
 568                     } else if (tag 
== "uses-sdk") { 
 569                         int32_t code 
= getIntegerAttribute(tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 572                             String8 name 
= getResolvedAttribute(&res
, tree
, MIN_SDK_VERSION_ATTR
, &error
); 
 574                                 fprintf(stderr
, "ERROR getting 'android:minSdkVersion' attribute: %s\n", 
 578                             printf("sdkVersion:'%s'\n", name
.string()); 
 579                         } else if (code 
!= -1) { 
 580                             printf("sdkVersion:'%d'\n", code
); 
 582                         code 
= getIntegerAttribute(tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 585                             String8 name 
= getResolvedAttribute(&res
, tree
, TARGET_SDK_VERSION_ATTR
, &error
); 
 587                                 fprintf(stderr
, "ERROR getting 'android:targetSdkVersion' attribute: %s\n", 
 591                             printf("targetSdkVersion:'%s'\n", name
.string()); 
 592                         } else if (code 
!= -1) { 
 593                             printf("targetSdkVersion:'%d'\n", code
); 
 595                     } else if (tag 
== "uses-configuration") { 
 596                         int32_t reqTouchScreen 
= getIntegerAttribute(tree
, 
 597                                 REQ_TOUCH_SCREEN_ATTR
, NULL
, 0); 
 598                         int32_t reqKeyboardType 
= getIntegerAttribute(tree
, 
 599                                 REQ_KEYBOARD_TYPE_ATTR
, NULL
, 0); 
 600                         int32_t reqHardKeyboard 
= getIntegerAttribute(tree
, 
 601                                 REQ_HARD_KEYBOARD_ATTR
, NULL
, 0); 
 602                         int32_t reqNavigation 
= getIntegerAttribute(tree
, 
 603                                 REQ_NAVIGATION_ATTR
, NULL
, 0); 
 604                         int32_t reqFiveWayNav 
= getIntegerAttribute(tree
, 
 605                                 REQ_FIVE_WAY_NAV_ATTR
, NULL
, 0); 
 606                         printf("uses-configuation:"); 
 607                         if (reqTouchScreen 
!= 0) { 
 608                             printf(" reqTouchScreen='%d'", reqTouchScreen
); 
 610                         if (reqKeyboardType 
!= 0) { 
 611                             printf(" reqKeyboardType='%d'", reqKeyboardType
); 
 613                         if (reqHardKeyboard 
!= 0) { 
 614                             printf(" reqHardKeyboard='%d'", reqHardKeyboard
); 
 616                         if (reqNavigation 
!= 0) { 
 617                             printf(" reqNavigation='%d'", reqNavigation
); 
 619                         if (reqFiveWayNav 
!= 0) { 
 620                             printf(" reqFiveWayNav='%d'", reqFiveWayNav
); 
 623                     } else if (tag 
== "supports-density") { 
 624                         int32_t dens 
= getIntegerAttribute(tree
, DENSITY_ATTR
, &error
); 
 626                             fprintf(stderr
, "ERROR getting 'android:density' attribute: %s\n", 
 630                         printf("supports-density:'%d'\n", dens
); 
 632                 } else if (depth 
== 3 && withinApplication
) { 
 633                     withinActivity 
= false; 
 634                     withinReceiver 
= false; 
 635                     if(tag 
== "activity") { 
 636                         withinActivity 
= true; 
 637                         activityName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 639                             fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
 643                         activityLabel 
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
); 
 645                             fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string()); 
 649                         activityIcon 
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
); 
 651                             fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string()); 
 654                     } else if (tag 
== "uses-library") { 
 655                         String8 libraryName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 657                             fprintf(stderr
, "ERROR getting 'android:name' attribute for uses-library: %s\n", error
.string()); 
 660                         printf("uses-library:'%s'\n", libraryName
.string()); 
 661                     } else if (tag 
== "receiver") { 
 662                         withinReceiver 
= true; 
 663                         receiverName 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 666                             fprintf(stderr
, "ERROR getting 'android:name' attribute for receiver: %s\n", error
.string()); 
 670                 } else if (depth 
== 5) { 
 671                     if (withinActivity
) { 
 672                         if (tag 
== "action") { 
 673                             //printf("LOG: action tag\n"); 
 674                             String8 action 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 676                                 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string()); 
 679                             if (action 
== "android.intent.action.MAIN") { 
 680                                 isMainActivity 
= true; 
 681                                 //printf("LOG: isMainActivity==true\n"); 
 683                         } else if (tag 
== "category") { 
 684                             String8 category 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 686                                 fprintf(stderr
, "ERROR getting 'name' attribute: %s\n", error
.string()); 
 689                             if (category 
== "android.intent.category.LAUNCHER") { 
 690                                 isLauncherActivity 
= true; 
 691                                 //printf("LOG: isLauncherActivity==true\n"); 
 694                     } else if (withinReceiver
) { 
 695                         if (tag 
== "action") { 
 696                             String8 action 
= getAttribute(tree
, NAME_ATTR
, &error
); 
 698                                 fprintf(stderr
, "ERROR getting 'android:name' attribute for receiver: %s\n", error
.string()); 
 701                             if (action 
== "android.appwidget.action.APPWIDGET_UPDATE") { 
 702                                 const char *rName 
= getComponentName(pkg
, receiverName
); 
 704                                     printf("gadget-receiver:'%s/%s'\n", pkg
.string(), rName
); 
 712                     withinApplication 
= false; 
 715                     //if (withinActivity) printf("LOG: withinActivity==false\n"); 
 716                     withinActivity 
= false; 
 717                     withinReceiver 
= false; 
 721                     //if (isMainActivity) printf("LOG: isMainActivity==false\n"); 
 722                     //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n"); 
 723                     isMainActivity 
= false; 
 724                     isLauncherActivity 
= false; 
 727                 if (withinActivity 
&& isMainActivity 
&& isLauncherActivity
) { 
 728                     printf("launchable activity:"); 
 729                     const char *aName 
= getComponentName(pkg
, activityName
); 
 731                         printf(" name='%s'", aName
); 
 733                     printf("label='%s' icon='%s'\n", 
 734                            activityLabel
.string(), 
 735                            activityIcon
.string()); 
 739             Vector
<String8
> locales
; 
 740             res
.getLocales(&locales
); 
 741             const size_t N 
= locales
.size(); 
 742             for (size_t i
=0; i
<N
; i
++) { 
 743                 const char* localeStr 
=  locales
[i
].string(); 
 744                 if (localeStr 
== NULL 
|| strlen(localeStr
) == 0) { 
 747                 printf(" '%s'", localeStr
); 
 750             AssetDir
* dir 
= assets
.openNonAssetDir(assetsCookie
, "lib"); 
 752                 if (dir
->getFileCount() > 0) { 
 753                     printf("native-code:"); 
 754                     for (size_t i
=0; i
<dir
->getFileCount(); i
++) { 
 755                         printf(" '%s'", dir
->getFileName(i
).string()); 
 761         } else if (strcmp("configurations", option
) == 0) { 
 762             Vector
<ResTable_config
> configs
; 
 763             res
.getConfigurations(&configs
); 
 764             const size_t N 
= configs
.size(); 
 765             for (size_t i
=0; i
<N
; i
++) { 
 766                 printf("%s\n", configs
[i
].toString().string()); 
 769             fprintf(stderr
, "ERROR: unknown dump option '%s'\n", option
); 
 780     return (result 
!= NO_ERROR
); 
 785  * Handle the "add" command, which wants to add files to a new or 
 786  * pre-existing archive. 
 788 int doAdd(Bundle
* bundle
) 
 791     status_t result 
= UNKNOWN_ERROR
; 
 792     const char* zipFileName
; 
 794     if (bundle
->getUpdate()) { 
 795         /* avoid confusion */ 
 796         fprintf(stderr
, "ERROR: can't use '-u' with add\n"); 
 800     if (bundle
->getFileSpecCount() < 1) { 
 801         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
 804     zipFileName 
= bundle
->getFileSpecEntry(0); 
 806     if (bundle
->getFileSpecCount() < 2) { 
 807         fprintf(stderr
, "NOTE: nothing to do\n"); 
 811     zip 
= openReadWrite(zipFileName
, true); 
 813         fprintf(stderr
, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName
); 
 817     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
 818         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
 820         if (strcasecmp(String8(fileName
).getPathExtension().string(), ".gz") == 0) { 
 821             printf(" '%s'... (from gzip)\n", fileName
); 
 822             result 
= zip
->addGzip(fileName
, String8(fileName
).getBasePath().string(), NULL
); 
 824             printf(" '%s'...\n", fileName
); 
 825             result 
= zip
->add(fileName
, bundle
->getCompressionMethod(), NULL
); 
 827         if (result 
!= NO_ERROR
) { 
 828             fprintf(stderr
, "Unable to add '%s' to '%s'", bundle
->getFileSpecEntry(i
), zipFileName
); 
 829             if (result 
== NAME_NOT_FOUND
) 
 830                 fprintf(stderr
, ": file not found\n"); 
 831             else if (result 
== ALREADY_EXISTS
) 
 832                 fprintf(stderr
, ": already exists in archive\n"); 
 834                 fprintf(stderr
, "\n"); 
 843     return (result 
!= NO_ERROR
); 
 848  * Delete files from an existing archive. 
 850 int doRemove(Bundle
* bundle
) 
 853     status_t result 
= UNKNOWN_ERROR
; 
 854     const char* zipFileName
; 
 856     if (bundle
->getFileSpecCount() < 1) { 
 857         fprintf(stderr
, "ERROR: must specify zip file name\n"); 
 860     zipFileName 
= bundle
->getFileSpecEntry(0); 
 862     if (bundle
->getFileSpecCount() < 2) { 
 863         fprintf(stderr
, "NOTE: nothing to do\n"); 
 867     zip 
= openReadWrite(zipFileName
, false); 
 869         fprintf(stderr
, "ERROR: failed opening Zip archive '%s'\n", 
 874     for (int i 
= 1; i 
< bundle
->getFileSpecCount(); i
++) { 
 875         const char* fileName 
= bundle
->getFileSpecEntry(i
); 
 878         entry 
= zip
->getEntryByName(fileName
); 
 880             printf(" '%s' NOT FOUND\n", fileName
); 
 884         result 
= zip
->remove(entry
); 
 886         if (result 
!= NO_ERROR
) { 
 887             fprintf(stderr
, "Unable to delete '%s' from '%s'\n", 
 888                 bundle
->getFileSpecEntry(i
), zipFileName
); 
 893     /* update the archive */ 
 898     return (result 
!= NO_ERROR
); 
 903  * Package up an asset directory and associated application files. 
 905 int doPackage(Bundle
* bundle
) 
 907     const char* outputAPKFile
; 
 910     sp
<AaptAssets
> assets
; 
 913     // -c zz_ZZ means do pseudolocalization 
 914     ResourceFilter filter
; 
 915     err 
= filter
.parse(bundle
->getConfigurations()); 
 916     if (err 
!= NO_ERROR
) { 
 919     if (filter
.containsPseudo()) { 
 920         bundle
->setPseudolocalize(true); 
 923     N 
= bundle
->getFileSpecCount(); 
 924     if (N 
< 1 && bundle
->getResourceSourceDirs().size() == 0 && bundle
->getJarFiles().size() == 0 
 925             && bundle
->getAndroidManifestFile() == NULL 
&& bundle
->getAssetSourceDir() == NULL
) { 
 926         fprintf(stderr
, "ERROR: no input files\n"); 
 930     outputAPKFile 
= bundle
->getOutputAPKFile(); 
 932     // Make sure the filenames provided exist and are of the appropriate type. 
 935         type 
= getFileType(outputAPKFile
); 
 936         if (type 
!= kFileTypeNonexistent 
&& type 
!= kFileTypeRegular
) { 
 938                 "ERROR: output file '%s' exists but is not regular file\n", 
 945     assets 
= new AaptAssets(); 
 946     err 
= assets
->slurpFromArgs(bundle
); 
 951     if (bundle
->getVerbose()) { 
 955     // If they asked for any files that need to be compiled, do so. 
 956     if (bundle
->getResourceSourceDirs().size() || bundle
->getAndroidManifestFile()) { 
 957         err 
= buildResources(bundle
, assets
); 
 963     // At this point we've read everything and processed everything.  From here 
 964     // on out it's just writing output files. 
 965     if (SourcePos::hasErrors()) { 
 969     // Write out R.java constants 
 970     if (assets
->getPackage() == assets
->getSymbolsPrivatePackage()) { 
 971         err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), true); 
 976         err 
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), false); 
 980         err 
= writeResourceSymbols(bundle
, assets
, assets
->getSymbolsPrivatePackage(), true); 
 988         err 
= writeAPK(bundle
, assets
, String8(outputAPKFile
)); 
 989         if (err 
!= NO_ERROR
) { 
 990             fprintf(stderr
, "ERROR: packaging of '%s' failed\n", outputAPKFile
); 
 997     if (SourcePos::hasErrors()) { 
 998         SourcePos::printErrors(stderr
);