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 VERSION_CODE_ATTR
= 0x0101021b,
349 VERSION_NAME_ATTR
= 0x0101021c,
350 SCREEN_ORIENTATION_ATTR
= 0x0101001e,
351 MIN_SDK_VERSION_ATTR
= 0x0101020c,
352 MAX_SDK_VERSION_ATTR
= 0x01010271,
353 REQ_TOUCH_SCREEN_ATTR
= 0x01010227,
354 REQ_KEYBOARD_TYPE_ATTR
= 0x01010228,
355 REQ_HARD_KEYBOARD_ATTR
= 0x01010229,
356 REQ_NAVIGATION_ATTR
= 0x0101022a,
357 REQ_FIVE_WAY_NAV_ATTR
= 0x01010232,
358 TARGET_SDK_VERSION_ATTR
= 0x01010270,
359 TEST_ONLY_ATTR
= 0x01010272,
360 ANY_DENSITY_ATTR
= 0x0101026c,
361 GL_ES_VERSION_ATTR
= 0x01010281,
362 SMALL_SCREEN_ATTR
= 0x01010284,
363 NORMAL_SCREEN_ATTR
= 0x01010285,
364 LARGE_SCREEN_ATTR
= 0x01010286,
365 XLARGE_SCREEN_ATTR
= 0x010102bf,
366 REQUIRED_ATTR
= 0x0101028e,
367 SCREEN_SIZE_ATTR
= 0x010102ca,
368 SCREEN_DENSITY_ATTR
= 0x010102cb,
369 REQUIRES_SMALLEST_WIDTH_DP_ATTR
= 0x01010364,
370 COMPATIBLE_WIDTH_LIMIT_DP_ATTR
= 0x01010365,
371 LARGEST_WIDTH_LIMIT_DP_ATTR
= 0x01010366,
372 PUBLIC_KEY_ATTR
= 0x010103a6,
375 const char *getComponentName(String8
&pkgName
, String8
&componentName
) {
376 ssize_t idx
= componentName
.find(".");
377 String8
retStr(pkgName
);
379 retStr
+= componentName
;
380 } else if (idx
< 0) {
382 retStr
+= componentName
;
384 return componentName
.string();
386 return retStr
.string();
389 static void printCompatibleScreens(ResXMLTree
& tree
) {
391 ResXMLTree::event_code_t code
;
394 printf("compatible-screens:");
395 while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT
&& code
!= ResXMLTree::BAD_DOCUMENT
) {
396 if (code
== ResXMLTree::END_TAG
) {
403 if (code
!= ResXMLTree::START_TAG
) {
407 String8
tag(tree
.getElementName(&len
));
408 if (tag
== "screen") {
409 int32_t screenSize
= getIntegerAttribute(tree
,
410 SCREEN_SIZE_ATTR
, NULL
, -1);
411 int32_t screenDensity
= getIntegerAttribute(tree
,
412 SCREEN_DENSITY_ATTR
, NULL
, -1);
413 if (screenSize
> 0 && screenDensity
> 0) {
418 printf("'%d/%d'", screenSize
, screenDensity
);
426 * Handle the "dump" command, to extract select data from an archive.
428 extern char CONSOLE_DATA
[2925]; // see EOF
429 int doDump(Bundle
* bundle
)
431 status_t result
= UNKNOWN_ERROR
;
434 if (bundle
->getFileSpecCount() < 1) {
435 fprintf(stderr
, "ERROR: no dump option specified\n");
439 if (bundle
->getFileSpecCount() < 2) {
440 fprintf(stderr
, "ERROR: no dump file specified\n");
444 const char* option
= bundle
->getFileSpecEntry(0);
445 const char* filename
= bundle
->getFileSpecEntry(1);
449 if (!assets
.addAssetPath(String8(filename
), &assetsCookie
)) {
450 fprintf(stderr
, "ERROR: dump failed because assets could not be loaded\n");
454 // Make a dummy config for retrieving resources... we need to supply
455 // non-default values for some configs so that we can retrieve resources
456 // in the app that don't have a default. The most important of these is
457 // the API version because key resources like icons will have an implicit
458 // version if they are using newer config types like density.
459 ResTable_config config
;
460 config
.language
[0] = 'e';
461 config
.language
[1] = 'n';
462 config
.country
[0] = 'U';
463 config
.country
[1] = 'S';
464 config
.orientation
= ResTable_config::ORIENTATION_PORT
;
465 config
.density
= ResTable_config::DENSITY_MEDIUM
;
466 config
.sdkVersion
= 10000; // Very high.
467 config
.screenWidthDp
= 320;
468 config
.screenHeightDp
= 480;
469 config
.smallestScreenWidthDp
= 320;
470 assets
.setConfiguration(config
);
472 const ResTable
& res
= assets
.getResources(false);
474 fprintf(stderr
, "ERROR: dump failed because no resource table was found\n");
478 if (strcmp("resources", option
) == 0) {
479 #ifndef HAVE_ANDROID_OS
480 res
.print(bundle
->getValues());
483 } else if (strcmp("strings", option
) == 0) {
484 const ResStringPool
* pool
= res
.getTableStringBlock(0);
485 printStringPool(pool
);
487 } else if (strcmp("xmltree", option
) == 0) {
488 if (bundle
->getFileSpecCount() < 3) {
489 fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n");
493 for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) {
494 const char* resname
= bundle
->getFileSpecEntry(i
);
496 asset
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
);
498 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
);
502 if (tree
.setTo(asset
->getBuffer(true),
503 asset
->getLength()) != NO_ERROR
) {
504 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
);
508 printXMLBlock(&tree
);
514 } else if (strcmp("xmlstrings", option
) == 0) {
515 if (bundle
->getFileSpecCount() < 3) {
516 fprintf(stderr
, "ERROR: no dump xmltree resource file specified\n");
520 for (int i
=2; i
<bundle
->getFileSpecCount(); i
++) {
521 const char* resname
= bundle
->getFileSpecEntry(i
);
523 asset
= assets
.openNonAsset(resname
, Asset::ACCESS_BUFFER
);
525 fprintf(stderr
, "ERROR: dump failed because resource %s found\n", resname
);
529 if (tree
.setTo(asset
->getBuffer(true),
530 asset
->getLength()) != NO_ERROR
) {
531 fprintf(stderr
, "ERROR: Resource %s is corrupt\n", resname
);
534 printStringPool(&tree
.getStrings());
541 asset
= assets
.openNonAsset("AndroidManifest.xml",
542 Asset::ACCESS_BUFFER
);
544 fprintf(stderr
, "ERROR: dump failed because no AndroidManifest.xml found\n");
548 if (tree
.setTo(asset
->getBuffer(true),
549 asset
->getLength()) != NO_ERROR
) {
550 fprintf(stderr
, "ERROR: AndroidManifest.xml is corrupt\n");
555 if (strcmp("permissions", option
) == 0) {
557 ResXMLTree::event_code_t code
;
559 while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT
&& code
!= ResXMLTree::BAD_DOCUMENT
) {
560 if (code
== ResXMLTree::END_TAG
) {
564 if (code
!= ResXMLTree::START_TAG
) {
568 String8
tag(tree
.getElementName(&len
));
569 //printf("Depth %d tag %s\n", depth, tag.string());
571 if (tag
!= "manifest") {
572 fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n");
575 String8 pkg
= getAttribute(tree
, NULL
, "package", NULL
);
576 printf("package: %s\n", pkg
.string());
577 } else if (depth
== 2 && tag
== "permission") {
579 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
581 fprintf(stderr
, "ERROR: %s\n", error
.string());
584 printf("permission: %s\n", name
.string());
585 } else if (depth
== 2 && tag
== "uses-permission") {
587 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
589 fprintf(stderr
, "ERROR: %s\n", error
.string());
592 printf("uses-permission: %s\n", name
.string());
595 } else if (strcmp("badging", option
) == 0) {
596 Vector
<String8
> locales
;
597 res
.getLocales(&locales
);
599 Vector
<ResTable_config
> configs
;
600 res
.getConfigurations(&configs
);
601 SortedVector
<int> densities
;
602 const size_t NC
= configs
.size();
603 for (size_t i
=0; i
<NC
; i
++) {
604 int dens
= configs
[i
].density
;
605 if (dens
== 0) dens
= 160;
610 ResXMLTree::event_code_t code
;
613 bool withinActivity
= false;
614 bool isMainActivity
= false;
615 bool isLauncherActivity
= false;
616 bool isSearchable
= false;
617 bool withinApplication
= false;
618 bool withinReceiver
= false;
619 bool withinService
= false;
620 bool withinIntentFilter
= false;
621 bool hasMainActivity
= false;
622 bool hasOtherActivities
= false;
623 bool hasOtherReceivers
= false;
624 bool hasOtherServices
= false;
625 bool hasWallpaperService
= false;
626 bool hasImeService
= false;
627 bool hasWidgetReceivers
= false;
628 bool hasIntentFilter
= false;
629 bool actMainActivity
= false;
630 bool actWidgetReceivers
= false;
631 bool actImeService
= false;
632 bool actWallpaperService
= false;
634 // These two implement the implicit permissions that are granted
635 // to pre-1.6 applications.
636 bool hasWriteExternalStoragePermission
= false;
637 bool hasReadPhoneStatePermission
= false;
639 // This next group of variables is used to implement a group of
640 // backward-compatibility heuristics necessitated by the addition of
641 // some new uses-feature constants in 2.1 and 2.2. In most cases, the
642 // heuristic is "if an app requests a permission but doesn't explicitly
643 // request the corresponding <uses-feature>, presume it's there anyway".
644 bool specCameraFeature
= false; // camera-related
645 bool specCameraAutofocusFeature
= false;
646 bool reqCameraAutofocusFeature
= false;
647 bool reqCameraFlashFeature
= false;
648 bool hasCameraPermission
= false;
649 bool specLocationFeature
= false; // location-related
650 bool specNetworkLocFeature
= false;
651 bool reqNetworkLocFeature
= false;
652 bool specGpsFeature
= false;
653 bool reqGpsFeature
= false;
654 bool hasMockLocPermission
= false;
655 bool hasCoarseLocPermission
= false;
656 bool hasGpsPermission
= false;
657 bool hasGeneralLocPermission
= false;
658 bool specBluetoothFeature
= false; // Bluetooth API-related
659 bool hasBluetoothPermission
= false;
660 bool specMicrophoneFeature
= false; // microphone-related
661 bool hasRecordAudioPermission
= false;
662 bool specWiFiFeature
= false;
663 bool hasWiFiPermission
= false;
664 bool specTelephonyFeature
= false; // telephony-related
665 bool reqTelephonySubFeature
= false;
666 bool hasTelephonyPermission
= false;
667 bool specTouchscreenFeature
= false; // touchscreen-related
668 bool specMultitouchFeature
= false;
669 bool reqDistinctMultitouchFeature
= false;
670 bool specScreenPortraitFeature
= false;
671 bool specScreenLandscapeFeature
= false;
672 bool reqScreenPortraitFeature
= false;
673 bool reqScreenLandscapeFeature
= false;
674 // 2.2 also added some other features that apps can request, but that
675 // have no corresponding permission, so we cannot implement any
676 // back-compatibility heuristic for them. The below are thus unnecessary
677 // (but are retained here for documentary purposes.)
678 //bool specCompassFeature = false;
679 //bool specAccelerometerFeature = false;
680 //bool specProximityFeature = false;
681 //bool specAmbientLightFeature = false;
682 //bool specLiveWallpaperFeature = false;
686 int normalScreen
= 1;
688 int xlargeScreen
= 1;
690 int requiresSmallestWidthDp
= 0;
691 int compatibleWidthLimitDp
= 0;
692 int largestWidthLimitDp
= 0;
694 String8 activityName
;
695 String8 activityLabel
;
696 String8 activityIcon
;
697 String8 receiverName
;
699 while ((code
=tree
.next()) != ResXMLTree::END_DOCUMENT
&& code
!= ResXMLTree::BAD_DOCUMENT
) {
700 if (code
== ResXMLTree::END_TAG
) {
703 withinApplication
= false;
704 } else if (depth
< 3) {
705 if (withinActivity
&& isMainActivity
&& isLauncherActivity
) {
706 const char *aName
= getComponentName(pkg
, activityName
);
707 printf("launchable-activity:");
709 printf(" name='%s' ", aName
);
711 printf(" label='%s' icon='%s'\n",
712 activityLabel
.string(),
713 activityIcon
.string());
715 if (!hasIntentFilter
) {
716 hasOtherActivities
|= withinActivity
;
717 hasOtherReceivers
|= withinReceiver
;
718 hasOtherServices
|= withinService
;
720 withinActivity
= false;
721 withinService
= false;
722 withinReceiver
= false;
723 hasIntentFilter
= false;
724 isMainActivity
= isLauncherActivity
= false;
725 } else if (depth
< 4) {
726 if (withinIntentFilter
) {
727 if (withinActivity
) {
728 hasMainActivity
|= actMainActivity
;
729 hasOtherActivities
|= !actMainActivity
;
730 } else if (withinReceiver
) {
731 hasWidgetReceivers
|= actWidgetReceivers
;
732 hasOtherReceivers
|= !actWidgetReceivers
;
733 } else if (withinService
) {
734 hasImeService
|= actImeService
;
735 hasWallpaperService
|= actWallpaperService
;
736 hasOtherServices
|= (!actImeService
&& !actWallpaperService
);
739 withinIntentFilter
= false;
743 if (code
!= ResXMLTree::START_TAG
) {
747 String8
tag(tree
.getElementName(&len
));
748 //printf("Depth %d, %s\n", depth, tag.string());
750 if (tag
!= "manifest") {
751 fprintf(stderr
, "ERROR: manifest does not start with <manifest> tag\n");
754 pkg
= getAttribute(tree
, NULL
, "package", NULL
);
755 printf("package: name='%s' ", pkg
.string());
756 int32_t versionCode
= getIntegerAttribute(tree
, VERSION_CODE_ATTR
, &error
);
758 fprintf(stderr
, "ERROR getting 'android:versionCode' attribute: %s\n", error
.string());
761 if (versionCode
> 0) {
762 printf("versionCode='%d' ", versionCode
);
764 printf("versionCode='' ");
766 String8 versionName
= getResolvedAttribute(&res
, tree
, VERSION_NAME_ATTR
, &error
);
768 fprintf(stderr
, "ERROR getting 'android:versionName' attribute: %s\n", error
.string());
771 printf("versionName='%s'\n", versionName
.string());
772 } else if (depth
== 2) {
773 withinApplication
= false;
774 if (tag
== "application") {
775 withinApplication
= true;
778 const size_t NL
= locales
.size();
779 for (size_t i
=0; i
<NL
; i
++) {
780 const char* localeStr
= locales
[i
].string();
781 assets
.setLocale(localeStr
!= NULL
? localeStr
: "");
782 String8 llabel
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
);
784 if (localeStr
== NULL
|| strlen(localeStr
) == 0) {
786 printf("application-label:'%s'\n", llabel
.string());
791 printf("application-label-%s:'%s'\n", localeStr
,
797 ResTable_config tmpConfig
= config
;
798 const size_t ND
= densities
.size();
799 for (size_t i
=0; i
<ND
; i
++) {
800 tmpConfig
.density
= densities
[i
];
801 assets
.setConfiguration(tmpConfig
);
802 String8 icon
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
);
804 printf("application-icon-%d:'%s'\n", densities
[i
], icon
.string());
807 assets
.setConfiguration(config
);
809 String8 icon
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
);
811 fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string());
814 int32_t testOnly
= getIntegerAttribute(tree
, TEST_ONLY_ATTR
, &error
, 0);
816 fprintf(stderr
, "ERROR getting 'android:testOnly' attribute: %s\n", error
.string());
819 printf("application: label='%s' ", label
.string());
820 printf("icon='%s'\n", icon
.string());
822 printf("testOnly='%d'\n", testOnly
);
824 } else if (tag
== "uses-sdk") {
825 int32_t code
= getIntegerAttribute(tree
, MIN_SDK_VERSION_ATTR
, &error
);
828 String8 name
= getResolvedAttribute(&res
, tree
, MIN_SDK_VERSION_ATTR
, &error
);
830 fprintf(stderr
, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
834 if (name
== "Donut") targetSdk
= 4;
835 printf("sdkVersion:'%s'\n", name
.string());
836 } else if (code
!= -1) {
838 printf("sdkVersion:'%d'\n", code
);
840 code
= getIntegerAttribute(tree
, MAX_SDK_VERSION_ATTR
, NULL
, -1);
842 printf("maxSdkVersion:'%d'\n", code
);
844 code
= getIntegerAttribute(tree
, TARGET_SDK_VERSION_ATTR
, &error
);
847 String8 name
= getResolvedAttribute(&res
, tree
, TARGET_SDK_VERSION_ATTR
, &error
);
849 fprintf(stderr
, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
853 if (name
== "Donut" && targetSdk
< 4) targetSdk
= 4;
854 printf("targetSdkVersion:'%s'\n", name
.string());
855 } else if (code
!= -1) {
856 if (targetSdk
< code
) {
859 printf("targetSdkVersion:'%d'\n", code
);
861 } else if (tag
== "uses-configuration") {
862 int32_t reqTouchScreen
= getIntegerAttribute(tree
,
863 REQ_TOUCH_SCREEN_ATTR
, NULL
, 0);
864 int32_t reqKeyboardType
= getIntegerAttribute(tree
,
865 REQ_KEYBOARD_TYPE_ATTR
, NULL
, 0);
866 int32_t reqHardKeyboard
= getIntegerAttribute(tree
,
867 REQ_HARD_KEYBOARD_ATTR
, NULL
, 0);
868 int32_t reqNavigation
= getIntegerAttribute(tree
,
869 REQ_NAVIGATION_ATTR
, NULL
, 0);
870 int32_t reqFiveWayNav
= getIntegerAttribute(tree
,
871 REQ_FIVE_WAY_NAV_ATTR
, NULL
, 0);
872 printf("uses-configuration:");
873 if (reqTouchScreen
!= 0) {
874 printf(" reqTouchScreen='%d'", reqTouchScreen
);
876 if (reqKeyboardType
!= 0) {
877 printf(" reqKeyboardType='%d'", reqKeyboardType
);
879 if (reqHardKeyboard
!= 0) {
880 printf(" reqHardKeyboard='%d'", reqHardKeyboard
);
882 if (reqNavigation
!= 0) {
883 printf(" reqNavigation='%d'", reqNavigation
);
885 if (reqFiveWayNav
!= 0) {
886 printf(" reqFiveWayNav='%d'", reqFiveWayNav
);
889 } else if (tag
== "supports-screens") {
890 smallScreen
= getIntegerAttribute(tree
,
891 SMALL_SCREEN_ATTR
, NULL
, 1);
892 normalScreen
= getIntegerAttribute(tree
,
893 NORMAL_SCREEN_ATTR
, NULL
, 1);
894 largeScreen
= getIntegerAttribute(tree
,
895 LARGE_SCREEN_ATTR
, NULL
, 1);
896 xlargeScreen
= getIntegerAttribute(tree
,
897 XLARGE_SCREEN_ATTR
, NULL
, 1);
898 anyDensity
= getIntegerAttribute(tree
,
899 ANY_DENSITY_ATTR
, NULL
, 1);
900 requiresSmallestWidthDp
= getIntegerAttribute(tree
,
901 REQUIRES_SMALLEST_WIDTH_DP_ATTR
, NULL
, 0);
902 compatibleWidthLimitDp
= getIntegerAttribute(tree
,
903 COMPATIBLE_WIDTH_LIMIT_DP_ATTR
, NULL
, 0);
904 largestWidthLimitDp
= getIntegerAttribute(tree
,
905 LARGEST_WIDTH_LIMIT_DP_ATTR
, NULL
, 0);
906 } else if (tag
== "uses-feature") {
907 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
909 if (name
!= "" && error
== "") {
910 int req
= getIntegerAttribute(tree
,
911 REQUIRED_ATTR
, NULL
, 1);
913 if (name
== "android.hardware.camera") {
914 specCameraFeature
= true;
915 } else if (name
== "android.hardware.camera.autofocus") {
916 // these have no corresponding permission to check for,
917 // but should imply the foundational camera permission
918 reqCameraAutofocusFeature
= reqCameraAutofocusFeature
|| req
;
919 specCameraAutofocusFeature
= true;
920 } else if (req
&& (name
== "android.hardware.camera.flash")) {
921 // these have no corresponding permission to check for,
922 // but should imply the foundational camera permission
923 reqCameraFlashFeature
= true;
924 } else if (name
== "android.hardware.location") {
925 specLocationFeature
= true;
926 } else if (name
== "android.hardware.location.network") {
927 specNetworkLocFeature
= true;
928 reqNetworkLocFeature
= reqNetworkLocFeature
|| req
;
929 } else if (name
== "android.hardware.location.gps") {
930 specGpsFeature
= true;
931 reqGpsFeature
= reqGpsFeature
|| req
;
932 } else if (name
== "android.hardware.bluetooth") {
933 specBluetoothFeature
= true;
934 } else if (name
== "android.hardware.touchscreen") {
935 specTouchscreenFeature
= true;
936 } else if (name
== "android.hardware.touchscreen.multitouch") {
937 specMultitouchFeature
= true;
938 } else if (name
== "android.hardware.touchscreen.multitouch.distinct") {
939 reqDistinctMultitouchFeature
= reqDistinctMultitouchFeature
|| req
;
940 } else if (name
== "android.hardware.microphone") {
941 specMicrophoneFeature
= true;
942 } else if (name
== "android.hardware.wifi") {
943 specWiFiFeature
= true;
944 } else if (name
== "android.hardware.telephony") {
945 specTelephonyFeature
= true;
946 } else if (req
&& (name
== "android.hardware.telephony.gsm" ||
947 name
== "android.hardware.telephony.cdma")) {
948 // these have no corresponding permission to check for,
949 // but should imply the foundational telephony permission
950 reqTelephonySubFeature
= true;
951 } else if (name
== "android.hardware.screen.portrait") {
952 specScreenPortraitFeature
= true;
953 } else if (name
== "android.hardware.screen.landscape") {
954 specScreenLandscapeFeature
= true;
956 printf("uses-feature%s:'%s'\n",
957 req
? "" : "-not-required", name
.string());
959 int vers
= getIntegerAttribute(tree
,
960 GL_ES_VERSION_ATTR
, &error
);
962 printf("uses-gl-es:'0x%x'\n", vers
);
965 } else if (tag
== "uses-permission") {
966 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
967 if (name
!= "" && error
== "") {
968 if (name
== "android.permission.CAMERA") {
969 hasCameraPermission
= true;
970 } else if (name
== "android.permission.ACCESS_FINE_LOCATION") {
971 hasGpsPermission
= true;
972 } else if (name
== "android.permission.ACCESS_MOCK_LOCATION") {
973 hasMockLocPermission
= true;
974 } else if (name
== "android.permission.ACCESS_COARSE_LOCATION") {
975 hasCoarseLocPermission
= true;
976 } else if (name
== "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
977 name
== "android.permission.INSTALL_LOCATION_PROVIDER") {
978 hasGeneralLocPermission
= true;
979 } else if (name
== "android.permission.BLUETOOTH" ||
980 name
== "android.permission.BLUETOOTH_ADMIN") {
981 hasBluetoothPermission
= true;
982 } else if (name
== "android.permission.RECORD_AUDIO") {
983 hasRecordAudioPermission
= true;
984 } else if (name
== "android.permission.ACCESS_WIFI_STATE" ||
985 name
== "android.permission.CHANGE_WIFI_STATE" ||
986 name
== "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
987 hasWiFiPermission
= true;
988 } else if (name
== "android.permission.CALL_PHONE" ||
989 name
== "android.permission.CALL_PRIVILEGED" ||
990 name
== "android.permission.MODIFY_PHONE_STATE" ||
991 name
== "android.permission.PROCESS_OUTGOING_CALLS" ||
992 name
== "android.permission.READ_SMS" ||
993 name
== "android.permission.RECEIVE_SMS" ||
994 name
== "android.permission.RECEIVE_MMS" ||
995 name
== "android.permission.RECEIVE_WAP_PUSH" ||
996 name
== "android.permission.SEND_SMS" ||
997 name
== "android.permission.WRITE_APN_SETTINGS" ||
998 name
== "android.permission.WRITE_SMS") {
999 hasTelephonyPermission
= true;
1000 } else if (name
== "android.permission.WRITE_EXTERNAL_STORAGE") {
1001 hasWriteExternalStoragePermission
= true;
1002 } else if (name
== "android.permission.READ_PHONE_STATE") {
1003 hasReadPhoneStatePermission
= true;
1005 printf("uses-permission:'%s'\n", name
.string());
1007 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n",
1011 } else if (tag
== "uses-package") {
1012 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
1013 if (name
!= "" && error
== "") {
1014 printf("uses-package:'%s'\n", name
.string());
1016 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n",
1020 } else if (tag
== "original-package") {
1021 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
1022 if (name
!= "" && error
== "") {
1023 printf("original-package:'%s'\n", name
.string());
1025 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n",
1029 } else if (tag
== "supports-gl-texture") {
1030 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
1031 if (name
!= "" && error
== "") {
1032 printf("supports-gl-texture:'%s'\n", name
.string());
1034 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n",
1038 } else if (tag
== "compatible-screens") {
1039 printCompatibleScreens(tree
);
1041 } else if (tag
== "package-verifier") {
1042 String8 name
= getAttribute(tree
, NAME_ATTR
, &error
);
1043 if (name
!= "" && error
== "") {
1044 String8 publicKey
= getAttribute(tree
, PUBLIC_KEY_ATTR
, &error
);
1045 if (publicKey
!= "" && error
== "") {
1046 printf("package-verifier: name='%s' publicKey='%s'\n",
1047 name
.string(), publicKey
.string());
1051 } else if (depth
== 3 && withinApplication
) {
1052 withinActivity
= false;
1053 withinReceiver
= false;
1054 withinService
= false;
1055 hasIntentFilter
= false;
1056 if(tag
== "activity") {
1057 withinActivity
= true;
1058 activityName
= getAttribute(tree
, NAME_ATTR
, &error
);
1060 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string());
1064 activityLabel
= getResolvedAttribute(&res
, tree
, LABEL_ATTR
, &error
);
1066 fprintf(stderr
, "ERROR getting 'android:label' attribute: %s\n", error
.string());
1070 activityIcon
= getResolvedAttribute(&res
, tree
, ICON_ATTR
, &error
);
1072 fprintf(stderr
, "ERROR getting 'android:icon' attribute: %s\n", error
.string());
1076 int32_t orien
= getResolvedIntegerAttribute(&res
, tree
,
1077 SCREEN_ORIENTATION_ATTR
, &error
);
1079 if (orien
== 0 || orien
== 6 || orien
== 8) {
1080 // Requests landscape, sensorLandscape, or reverseLandscape.
1081 reqScreenLandscapeFeature
= true;
1082 } else if (orien
== 1 || orien
== 7 || orien
== 9) {
1083 // Requests portrait, sensorPortrait, or reversePortrait.
1084 reqScreenPortraitFeature
= true;
1087 } else if (tag
== "uses-library") {
1088 String8 libraryName
= getAttribute(tree
, NAME_ATTR
, &error
);
1090 fprintf(stderr
, "ERROR getting 'android:name' attribute for uses-library: %s\n", error
.string());
1093 int req
= getIntegerAttribute(tree
,
1094 REQUIRED_ATTR
, NULL
, 1);
1095 printf("uses-library%s:'%s'\n",
1096 req
? "" : "-not-required", libraryName
.string());
1097 } else if (tag
== "receiver") {
1098 withinReceiver
= true;
1099 receiverName
= getAttribute(tree
, NAME_ATTR
, &error
);
1102 fprintf(stderr
, "ERROR getting 'android:name' attribute for receiver: %s\n", error
.string());
1105 } else if (tag
== "service") {
1106 withinService
= true;
1107 serviceName
= getAttribute(tree
, NAME_ATTR
, &error
);
1110 fprintf(stderr
, "ERROR getting 'android:name' attribute for service: %s\n", error
.string());
1114 } else if ((depth
== 4) && (tag
== "intent-filter")) {
1115 hasIntentFilter
= true;
1116 withinIntentFilter
= true;
1117 actMainActivity
= actWidgetReceivers
= actImeService
= actWallpaperService
= false;
1118 } else if ((depth
== 5) && withinIntentFilter
){
1120 if (tag
== "action") {
1121 action
= getAttribute(tree
, NAME_ATTR
, &error
);
1123 fprintf(stderr
, "ERROR getting 'android:name' attribute: %s\n", error
.string());
1126 if (withinActivity
) {
1127 if (action
== "android.intent.action.MAIN") {
1128 isMainActivity
= true;
1129 actMainActivity
= true;
1131 } else if (withinReceiver
) {
1132 if (action
== "android.appwidget.action.APPWIDGET_UPDATE") {
1133 actWidgetReceivers
= true;
1135 } else if (withinService
) {
1136 if (action
== "android.view.InputMethod") {
1137 actImeService
= true;
1138 } else if (action
== "android.service.wallpaper.WallpaperService") {
1139 actWallpaperService
= true;
1142 if (action
== "android.intent.action.SEARCH") {
1143 isSearchable
= true;
1147 if (tag
== "category") {
1148 String8 category
= getAttribute(tree
, NAME_ATTR
, &error
);
1150 fprintf(stderr
, "ERROR getting 'name' attribute: %s\n", error
.string());
1153 if (withinActivity
) {
1154 if (category
== "android.intent.category.LAUNCHER") {
1155 isLauncherActivity
= true;
1162 // Pre-1.6 implicitly granted permission compatibility logic
1163 if (targetSdk
< 4) {
1164 if (!hasWriteExternalStoragePermission
) {
1165 printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
1167 if (!hasReadPhoneStatePermission
) {
1168 printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
1172 /* The following blocks handle printing "inferred" uses-features, based
1173 * on whether related features or permissions are used by the app.
1174 * Note that the various spec*Feature variables denote whether the
1175 * relevant tag was *present* in the AndroidManfest, not that it was
1176 * present and set to true.
1178 // Camera-related back-compatibility logic
1179 if (!specCameraFeature
) {
1180 if (reqCameraFlashFeature
|| reqCameraAutofocusFeature
) {
1181 // if app requested a sub-feature (autofocus or flash) and didn't
1182 // request the base camera feature, we infer that it meant to
1183 printf("uses-feature:'android.hardware.camera'\n");
1184 } else if (hasCameraPermission
) {
1185 // if app wants to use camera but didn't request the feature, we infer
1186 // that it meant to, and further that it wants autofocus
1187 // (which was the 1.0 - 1.5 behavior)
1188 printf("uses-feature:'android.hardware.camera'\n");
1189 if (!specCameraAutofocusFeature
) {
1190 printf("uses-feature:'android.hardware.camera.autofocus'\n");
1195 // Location-related back-compatibility logic
1196 if (!specLocationFeature
&&
1197 (hasMockLocPermission
|| hasCoarseLocPermission
|| hasGpsPermission
||
1198 hasGeneralLocPermission
|| reqNetworkLocFeature
|| reqGpsFeature
)) {
1199 // if app either takes a location-related permission or requests one of the
1200 // sub-features, we infer that it also meant to request the base location feature
1201 printf("uses-feature:'android.hardware.location'\n");
1203 if (!specGpsFeature
&& hasGpsPermission
) {
1204 // if app takes GPS (FINE location) perm but does not request the GPS
1205 // feature, we infer that it meant to
1206 printf("uses-feature:'android.hardware.location.gps'\n");
1208 if (!specNetworkLocFeature
&& hasCoarseLocPermission
) {
1209 // if app takes Network location (COARSE location) perm but does not request the
1210 // network location feature, we infer that it meant to
1211 printf("uses-feature:'android.hardware.location.network'\n");
1214 // Bluetooth-related compatibility logic
1215 if (!specBluetoothFeature
&& hasBluetoothPermission
&& (targetSdk
> 4)) {
1216 // if app takes a Bluetooth permission but does not request the Bluetooth
1217 // feature, we infer that it meant to
1218 printf("uses-feature:'android.hardware.bluetooth'\n");
1221 // Microphone-related compatibility logic
1222 if (!specMicrophoneFeature
&& hasRecordAudioPermission
) {
1223 // if app takes the record-audio permission but does not request the microphone
1224 // feature, we infer that it meant to
1225 printf("uses-feature:'android.hardware.microphone'\n");
1228 // WiFi-related compatibility logic
1229 if (!specWiFiFeature
&& hasWiFiPermission
) {
1230 // if app takes one of the WiFi permissions but does not request the WiFi
1231 // feature, we infer that it meant to
1232 printf("uses-feature:'android.hardware.wifi'\n");
1235 // Telephony-related compatibility logic
1236 if (!specTelephonyFeature
&& (hasTelephonyPermission
|| reqTelephonySubFeature
)) {
1237 // if app takes one of the telephony permissions or requests a sub-feature but
1238 // does not request the base telephony feature, we infer that it meant to
1239 printf("uses-feature:'android.hardware.telephony'\n");
1242 // Touchscreen-related back-compatibility logic
1243 if (!specTouchscreenFeature
) { // not a typo!
1244 // all apps are presumed to require a touchscreen, unless they explicitly say
1245 // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
1246 // Note that specTouchscreenFeature is true if the tag is present, regardless
1247 // of whether its value is true or false, so this is safe
1248 printf("uses-feature:'android.hardware.touchscreen'\n");
1250 if (!specMultitouchFeature
&& reqDistinctMultitouchFeature
) {
1251 // if app takes one of the telephony permissions or requests a sub-feature but
1252 // does not request the base telephony feature, we infer that it meant to
1253 printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
1256 // Landscape/portrait-related compatibility logic
1257 if (!specScreenLandscapeFeature
&& !specScreenPortraitFeature
) {
1258 // If the app has specified any activities in its manifest
1259 // that request a specific orientation, then assume that
1260 // orientation is required.
1261 if (reqScreenLandscapeFeature
) {
1262 printf("uses-feature:'android.hardware.screen.landscape'\n");
1264 if (reqScreenPortraitFeature
) {
1265 printf("uses-feature:'android.hardware.screen.portrait'\n");
1269 if (hasMainActivity
) {
1272 if (hasWidgetReceivers
) {
1273 printf("app-widget\n");
1275 if (hasImeService
) {
1278 if (hasWallpaperService
) {
1279 printf("wallpaper\n");
1281 if (hasOtherActivities
) {
1282 printf("other-activities\n");
1287 if (hasOtherReceivers
) {
1288 printf("other-receivers\n");
1290 if (hasOtherServices
) {
1291 printf("other-services\n");
1294 // For modern apps, if screen size buckets haven't been specified
1295 // but the new width ranges have, then infer the buckets from them.
1296 if (smallScreen
> 0 && normalScreen
> 0 && largeScreen
> 0 && xlargeScreen
> 0
1297 && requiresSmallestWidthDp
> 0) {
1298 int compatWidth
= compatibleWidthLimitDp
;
1299 if (compatWidth
<= 0) compatWidth
= requiresSmallestWidthDp
;
1300 if (requiresSmallestWidthDp
<= 240 && compatWidth
>= 240) {
1305 if (requiresSmallestWidthDp
<= 320 && compatWidth
>= 320) {
1310 if (requiresSmallestWidthDp
<= 480 && compatWidth
>= 480) {
1315 if (requiresSmallestWidthDp
<= 720 && compatWidth
>= 720) {
1322 // Determine default values for any unspecified screen sizes,
1323 // based on the target SDK of the package. As of 4 (donut)
1324 // the screen size support was introduced, so all default to
1326 if (smallScreen
> 0) {
1327 smallScreen
= targetSdk
>= 4 ? -1 : 0;
1329 if (normalScreen
> 0) {
1332 if (largeScreen
> 0) {
1333 largeScreen
= targetSdk
>= 4 ? -1 : 0;
1335 if (xlargeScreen
> 0) {
1336 // Introduced in Gingerbread.
1337 xlargeScreen
= targetSdk
>= 9 ? -1 : 0;
1339 if (anyDensity
> 0) {
1340 anyDensity
= (targetSdk
>= 4 || requiresSmallestWidthDp
> 0
1341 || compatibleWidthLimitDp
> 0) ? -1 : 0;
1343 printf("supports-screens:");
1344 if (smallScreen
!= 0) printf(" 'small'");
1345 if (normalScreen
!= 0) printf(" 'normal'");
1346 if (largeScreen
!= 0) printf(" 'large'");
1347 if (xlargeScreen
!= 0) printf(" 'xlarge'");
1349 printf("supports-any-density: '%s'\n", anyDensity
? "true" : "false");
1350 if (requiresSmallestWidthDp
> 0) {
1351 printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp
);
1353 if (compatibleWidthLimitDp
> 0) {
1354 printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp
);
1356 if (largestWidthLimitDp
> 0) {
1357 printf("largest-width-limit:'%d'\n", largestWidthLimitDp
);
1361 const size_t NL
= locales
.size();
1362 for (size_t i
=0; i
<NL
; i
++) {
1363 const char* localeStr
= locales
[i
].string();
1364 if (localeStr
== NULL
|| strlen(localeStr
) == 0) {
1365 localeStr
= "--_--";
1367 printf(" '%s'", localeStr
);
1371 printf("densities:");
1372 const size_t ND
= densities
.size();
1373 for (size_t i
=0; i
<ND
; i
++) {
1374 printf(" '%d'", densities
[i
]);
1378 AssetDir
* dir
= assets
.openNonAssetDir(assetsCookie
, "lib");
1380 if (dir
->getFileCount() > 0) {
1381 printf("native-code:");
1382 for (size_t i
=0; i
<dir
->getFileCount(); i
++) {
1383 printf(" '%s'", dir
->getFileName(i
).string());
1389 } else if (strcmp("badger", option
) == 0) {
1390 printf("%s", CONSOLE_DATA
);
1391 } else if (strcmp("configurations", option
) == 0) {
1392 Vector
<ResTable_config
> configs
;
1393 res
.getConfigurations(&configs
);
1394 const size_t N
= configs
.size();
1395 for (size_t i
=0; i
<N
; i
++) {
1396 printf("%s\n", configs
[i
].toString().string());
1399 fprintf(stderr
, "ERROR: unknown dump option '%s'\n", option
);
1410 return (result
!= NO_ERROR
);
1415 * Handle the "add" command, which wants to add files to a new or
1416 * pre-existing archive.
1418 int doAdd(Bundle
* bundle
)
1420 ZipFile
* zip
= NULL
;
1421 status_t result
= UNKNOWN_ERROR
;
1422 const char* zipFileName
;
1424 if (bundle
->getUpdate()) {
1425 /* avoid confusion */
1426 fprintf(stderr
, "ERROR: can't use '-u' with add\n");
1430 if (bundle
->getFileSpecCount() < 1) {
1431 fprintf(stderr
, "ERROR: must specify zip file name\n");
1434 zipFileName
= bundle
->getFileSpecEntry(0);
1436 if (bundle
->getFileSpecCount() < 2) {
1437 fprintf(stderr
, "NOTE: nothing to do\n");
1441 zip
= openReadWrite(zipFileName
, true);
1443 fprintf(stderr
, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName
);
1447 for (int i
= 1; i
< bundle
->getFileSpecCount(); i
++) {
1448 const char* fileName
= bundle
->getFileSpecEntry(i
);
1450 if (strcasecmp(String8(fileName
).getPathExtension().string(), ".gz") == 0) {
1451 printf(" '%s'... (from gzip)\n", fileName
);
1452 result
= zip
->addGzip(fileName
, String8(fileName
).getBasePath().string(), NULL
);
1454 if (bundle
->getJunkPath()) {
1455 String8 storageName
= String8(fileName
).getPathLeaf();
1456 printf(" '%s' as '%s'...\n", fileName
, storageName
.string());
1457 result
= zip
->add(fileName
, storageName
.string(),
1458 bundle
->getCompressionMethod(), NULL
);
1460 printf(" '%s'...\n", fileName
);
1461 result
= zip
->add(fileName
, bundle
->getCompressionMethod(), NULL
);
1464 if (result
!= NO_ERROR
) {
1465 fprintf(stderr
, "Unable to add '%s' to '%s'", bundle
->getFileSpecEntry(i
), zipFileName
);
1466 if (result
== NAME_NOT_FOUND
)
1467 fprintf(stderr
, ": file not found\n");
1468 else if (result
== ALREADY_EXISTS
)
1469 fprintf(stderr
, ": already exists in archive\n");
1471 fprintf(stderr
, "\n");
1480 return (result
!= NO_ERROR
);
1485 * Delete files from an existing archive.
1487 int doRemove(Bundle
* bundle
)
1489 ZipFile
* zip
= NULL
;
1490 status_t result
= UNKNOWN_ERROR
;
1491 const char* zipFileName
;
1493 if (bundle
->getFileSpecCount() < 1) {
1494 fprintf(stderr
, "ERROR: must specify zip file name\n");
1497 zipFileName
= bundle
->getFileSpecEntry(0);
1499 if (bundle
->getFileSpecCount() < 2) {
1500 fprintf(stderr
, "NOTE: nothing to do\n");
1504 zip
= openReadWrite(zipFileName
, false);
1506 fprintf(stderr
, "ERROR: failed opening Zip archive '%s'\n",
1511 for (int i
= 1; i
< bundle
->getFileSpecCount(); i
++) {
1512 const char* fileName
= bundle
->getFileSpecEntry(i
);
1515 entry
= zip
->getEntryByName(fileName
);
1516 if (entry
== NULL
) {
1517 printf(" '%s' NOT FOUND\n", fileName
);
1521 result
= zip
->remove(entry
);
1523 if (result
!= NO_ERROR
) {
1524 fprintf(stderr
, "Unable to delete '%s' from '%s'\n",
1525 bundle
->getFileSpecEntry(i
), zipFileName
);
1530 /* update the archive */
1535 return (result
!= NO_ERROR
);
1540 * Package up an asset directory and associated application files.
1542 int doPackage(Bundle
* bundle
)
1544 const char* outputAPKFile
;
1547 sp
<AaptAssets
> assets
;
1550 String8 dependencyFile
;
1552 // -c zz_ZZ means do pseudolocalization
1553 ResourceFilter filter
;
1554 err
= filter
.parse(bundle
->getConfigurations());
1555 if (err
!= NO_ERROR
) {
1558 if (filter
.containsPseudo()) {
1559 bundle
->setPseudolocalize(true);
1562 N
= bundle
->getFileSpecCount();
1563 if (N
< 1 && bundle
->getResourceSourceDirs().size() == 0 && bundle
->getJarFiles().size() == 0
1564 && bundle
->getAndroidManifestFile() == NULL
&& bundle
->getAssetSourceDir() == NULL
) {
1565 fprintf(stderr
, "ERROR: no input files\n");
1569 outputAPKFile
= bundle
->getOutputAPKFile();
1571 // Make sure the filenames provided exist and are of the appropriate type.
1572 if (outputAPKFile
) {
1574 type
= getFileType(outputAPKFile
);
1575 if (type
!= kFileTypeNonexistent
&& type
!= kFileTypeRegular
) {
1577 "ERROR: output file '%s' exists but is not regular file\n",
1584 assets
= new AaptAssets();
1586 // Set up the resource gathering in assets if we're going to generate
1587 // dependency files. Every time we encounter a resource while slurping
1588 // the tree, we'll add it to these stores so we have full resource paths
1589 // to write to a dependency file.
1590 if (bundle
->getGenDependencies()) {
1591 sp
<FilePathStore
> resPathStore
= new FilePathStore
;
1592 assets
->setFullResPaths(resPathStore
);
1593 sp
<FilePathStore
> assetPathStore
= new FilePathStore
;
1594 assets
->setFullAssetPaths(assetPathStore
);
1597 err
= assets
->slurpFromArgs(bundle
);
1602 if (bundle
->getVerbose()) {
1603 assets
->print(String8());
1606 // If they asked for any fileAs that need to be compiled, do so.
1607 if (bundle
->getResourceSourceDirs().size() || bundle
->getAndroidManifestFile()) {
1608 err
= buildResources(bundle
, assets
);
1614 // At this point we've read everything and processed everything. From here
1615 // on out it's just writing output files.
1616 if (SourcePos::hasErrors()) {
1620 // Update symbols with information about which ones are needed as Java symbols.
1621 assets
->applyJavaSymbols();
1622 if (SourcePos::hasErrors()) {
1626 // If we've been asked to generate a dependency file, do that here
1627 if (bundle
->getGenDependencies()) {
1628 // If this is the packaging step, generate the dependency file next to
1629 // the output apk (e.g. bin/resources.ap_.d)
1630 if (outputAPKFile
) {
1631 dependencyFile
= String8(outputAPKFile
);
1632 // Add the .d extension to the dependency file.
1633 dependencyFile
.append(".d");
1635 // Else if this is the R.java dependency generation step,
1636 // generate the dependency file in the R.java package subdirectory
1637 // e.g. gen/com/foo/app/R.java.d
1638 dependencyFile
= String8(bundle
->getRClassDir());
1639 dependencyFile
.appendPath("R.java.d");
1641 // Make sure we have a clean dependency file to start with
1642 fp
= fopen(dependencyFile
, "w");
1646 // Write out R.java constants
1647 if (!assets
->havePrivateSymbols()) {
1648 if (bundle
->getCustomPackage() == NULL
) {
1649 // Write the R.java file into the appropriate class directory
1650 // e.g. gen/com/foo/app/R.java
1651 err
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), true);
1652 // If we have library files, we're going to write our R.java file into
1653 // the appropriate class directory for those libraries as well.
1654 // e.g. gen/com/foo/app/lib/R.java
1655 if (bundle
->getExtraPackages() != NULL
) {
1657 String8
libs(bundle
->getExtraPackages());
1658 char* packageString
= strtok(libs
.lockBuffer(libs
.length()), ":");
1659 while (packageString
!= NULL
) {
1660 // Write the R.java file out with the correct package name
1661 err
= writeResourceSymbols(bundle
, assets
, String8(packageString
), true);
1662 packageString
= strtok(NULL
, ":");
1664 libs
.unlockBuffer();
1667 const String8
customPkg(bundle
->getCustomPackage());
1668 err
= writeResourceSymbols(bundle
, assets
, customPkg
, true);
1674 err
= writeResourceSymbols(bundle
, assets
, assets
->getPackage(), false);
1678 err
= writeResourceSymbols(bundle
, assets
, assets
->getSymbolsPrivatePackage(), true);
1684 // Write out the ProGuard file
1685 err
= writeProguardFile(bundle
, assets
);
1691 if (outputAPKFile
) {
1692 err
= writeAPK(bundle
, assets
, String8(outputAPKFile
));
1693 if (err
!= NO_ERROR
) {
1694 fprintf(stderr
, "ERROR: packaging of '%s' failed\n", outputAPKFile
);
1699 // If we've been asked to generate a dependency file, we need to finish up here.
1700 // the writeResourceSymbols and writeAPK functions have already written the target
1701 // half of the dependency file, now we need to write the prerequisites. (files that
1702 // the R.java file or .ap_ file depend on)
1703 if (bundle
->getGenDependencies()) {
1704 // Now that writeResourceSymbols or writeAPK has taken care of writing
1705 // the targets to our dependency file, we'll write the prereqs
1706 fp
= fopen(dependencyFile
, "a+");
1708 bool includeRaw
= (outputAPKFile
!= NULL
);
1709 err
= writeDependencyPreReqs(bundle
, assets
, fp
, includeRaw
);
1710 // Also manually add the AndroidManifeset since it's not under res/ or assets/
1711 // and therefore was not added to our pathstores during slurping
1712 fprintf(fp
, "%s \\\n", bundle
->getAndroidManifestFile());
1718 if (SourcePos::hasErrors()) {
1719 SourcePos::printErrors(stderr
);
1727 * -S flag points to a source directory containing drawable* folders
1728 * -C flag points to destination directory. The folder structure in the
1729 * source directory will be mirrored to the destination (cache) directory
1732 * Destination directory will be updated to match the PNG files in
1733 * the source directory.
1735 int doCrunch(Bundle
* bundle
)
1737 fprintf(stdout
, "Crunching PNG Files in ");
1738 fprintf(stdout
, "source dir: %s\n", bundle
->getResourceSourceDirs()[0]);
1739 fprintf(stdout
, "To destination dir: %s\n", bundle
->getCrunchedOutputDir());
1741 updatePreProcessedCache(bundle
);
1746 char CONSOLE_DATA
[2925] = {
1747 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1748 32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1749 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1750 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
1751 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
1752 86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
1753 62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1754 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1755 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
1756 81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
1757 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
1758 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1759 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
1760 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1761 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1762 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
1763 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
1764 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1765 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1766 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
1767 58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
1768 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
1769 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
1770 47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
1771 121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1772 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1773 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
1774 81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
1775 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
1776 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1777 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
1778 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1779 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1780 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
1781 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
1782 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1783 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1784 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
1785 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
1786 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
1787 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1788 32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
1789 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1790 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1791 32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
1792 81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
1793 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
1794 32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
1795 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
1796 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1797 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
1798 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
1799 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
1800 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1801 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
1802 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
1803 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
1804 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
1805 67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
1806 59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
1807 61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
1808 32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
1809 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
1810 73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
1811 59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
1812 32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
1813 59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
1814 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
1815 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
1816 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
1817 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
1818 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
1819 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1820 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
1821 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
1822 59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
1823 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1824 32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
1825 81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
1826 87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
1827 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
1828 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
1829 45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
1830 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1831 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
1832 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
1833 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
1834 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
1835 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
1836 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1837 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1838 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
1839 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
1840 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1841 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1842 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
1843 81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1844 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
1845 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
1846 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
1847 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1848 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1849 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
1850 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
1851 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
1852 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1853 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
1854 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1855 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1856 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
1857 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
1858 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1859 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1860 32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
1861 81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1862 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
1863 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
1864 59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
1865 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1866 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1867 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
1868 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
1869 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
1870 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
1871 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
1872 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
1873 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
1874 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
1875 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
1876 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1877 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1878 32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
1879 59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
1880 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
1881 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
1882 59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
1883 59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1884 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1885 32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
1886 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
1887 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
1888 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1889 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
1890 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1891 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
1892 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
1893 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
1894 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1895 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1896 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
1897 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
1898 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
1899 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
1900 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
1901 59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1902 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1903 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
1904 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
1905 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1906 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1907 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1908 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1909 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10