Command.cpp revision 9266c558bf1d21ff647525ff99f7dadbca417309
1bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber// 2bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber// Copyright 2006 The Android Open Source Project 3bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber// 4bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber// Android Asset Packaging Tool main entry point. 5bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber// 6bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include "Main.h" 7bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include "Bundle.h" 8bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include "ResourceTable.h" 9bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include "XMLNode.h" 10bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 11bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include <utils.h> 12bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include <utils/ZipFile.h> 13bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 14bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include <fcntl.h> 15bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber#include <errno.h> 16bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 176c00983982d167bdb348c437f0480a480f38696cGlenn Kastenusing namespace android; 18eabd34665adc284525fe7337ad5c56a8b92964efGlenn Kasten 19bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber/* 20bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber * Show version info. All the cool kids do it. 212163320110d2f971becbad82e15b2ab360a1ddb6Jamie Gennis */ 22377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETITint doVersion(Bundle* bundle) 23bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 242163320110d2f971becbad82e15b2ab360a1ddb6Jamie Gennis if (bundle->getFileSpecCount() != 0) 25bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber printf("(ignoring extra arguments)\n"); 26988e3f0b2c74095deae580157c57935a98573052Andreas Huber printf("Android Asset Packaging Tool, v0.2\n"); 27988e3f0b2c74095deae580157c57935a98573052Andreas Huber 28bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return 0; 29681755fc0d0797506456f46a2a10555916d6be32Andreas Huber} 30733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber 310a5baa9b411fe086013d2a5e9126ed63fbad046cAndreas Huber 320a5baa9b411fe086013d2a5e9126ed63fbad046cAndreas Huber/* 33bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber * Open the file read only. The call fails if the file doesn't exist. 34681755fc0d0797506456f46a2a10555916d6be32Andreas Huber * 35bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber * Returns NULL on failure. 364844ac54e8b5997c3b03872dbafe8ebed4787517Andreas Huber */ 377cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria WangZipFile* openReadOnly(const char* fileName) 381b86fe063badb5f28c467ade39be0f4008688947Andreas Huber{ 391b86fe063badb5f28c467ade39be0f4008688947Andreas Huber ZipFile* zip; 407cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang status_t result; 41e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber 42e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber zip = new ZipFile; 433254b25e8b0f674ccc2226609e01dd86a600802eInsun Kang result = zip->open(fileName, ZipFile::kOpenReadOnly); 44bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (result != NO_ERROR) { 45bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (result == NAME_NOT_FOUND) 46bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fprintf(stderr, "ERROR: '%s' not found\n", fileName); 47bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber else if (result == PERMISSION_DENIED) 48717826ececd8d39596f62418677721d70776add1Andreas Huber fprintf(stderr, "ERROR: '%s' access denied\n", fileName); 49bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber else 501b86fe063badb5f28c467ade39be0f4008688947Andreas Huber fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n", 51bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fileName); 52bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber delete zip; 53bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return NULL; 5494ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald } 55717826ececd8d39596f62418677721d70776add1Andreas Huber 568ba01021b573889802e67e029225a96f0dfa471aAndy McFadden return zip; 571a2952aee048ca7b1765e2bc09ebe9aeddaeafa3Mathias Agopian} 583cf613507f1e2f7bd932d921a6e222e426fd3be4Mathias Agopian 5914acc736e336cbd6026df781d4f411e908831815Andreas Huber/* 60e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Open the file read-write. The file will be created if it doesn't 61eabd34665adc284525fe7337ad5c56a8b92964efGlenn Kasten * already exist and "okayToCreate" is set. 62eabd34665adc284525fe7337ad5c56a8b92964efGlenn Kasten * 63e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber * Returns NULL on failure. 6414f95746466fb6abdbbf33ee26d92ebf3fbef98fJames Dong */ 65e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas HuberZipFile* openReadWrite(const char* fileName, bool okayToCreate) 66bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 67bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber ZipFile* zip = NULL; 688650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber status_t result; 6983ed9d41b5aea53a5f3f0ae2fa14e101c079a12aGloria Wang int flags; 70ac05c317cd818701535c5d72ce90da98c4bae75bAndreas Huber 71ac05c317cd818701535c5d72ce90da98c4bae75bAndreas Huber flags = ZipFile::kOpenReadWrite; 728650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (okayToCreate) 7394ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald flags |= ZipFile::kOpenCreate; 7494ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald 7594ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald zip = new ZipFile; 7694ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald result = zip->open(fileName, flags); 7794ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald if (result != NO_ERROR) { 78bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber delete zip; 79c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber zip = NULL; 80c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber goto bail; 81c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber } 82bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 83c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huberbail: 84bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return zip; 85bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber} 86bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 87bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 88bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber/* 8984333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber * Return a short string describing the compression method. 90c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber */ 91bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huberconst char* compressionName(int method) 92bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 93bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (method == ZipEntry::kCompressStored) 94bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return "Stored"; 95c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber else if (method == ZipEntry::kCompressDeflated) 96bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return "Deflated"; 97bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber else 98bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return "Unknown"; 99bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber} 100bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 101733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber/* 102733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber * Return the percent reduction in size (0% == no compression). 1031173118eace0e9e347cb007f0da817cee87579edGlenn Kasten */ 1041173118eace0e9e347cb007f0da817cee87579edGlenn Kastenint calcPercent(long uncompressedLen, long compressedLen) 105733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber{ 106733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber if (!uncompressedLen) 107733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber return 0; 108fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber else 109fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5); 110fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber} 111fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber 112fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber/* 113fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber * Handle the "list" command, which can be a simple file dump or 114733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber * a verbose listing. 115733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber * 116733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber * The verbose listing closely matches the output of the Info-ZIP "unzip" 117733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber * command. 118733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber */ 119733b7729ea462fae9c6899456444e28fef1c757cAndreas Huberint doList(Bundle* bundle) 120733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber{ 121733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber int result = 1; 122733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber ZipFile* zip = NULL; 1230a5ca668c6f7d45706e9aec4a1dfec0aacc6d233Andreas Huber const ZipEntry* entry; 124988e3f0b2c74095deae580157c57935a98573052Andreas Huber long totalUncLen, totalCompLen; 125733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber const char* zipFileName; 126733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber 127733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber if (bundle->getFileSpecCount() != 1) { 128733b7729ea462fae9c6899456444e28fef1c757cAndreas Huber fprintf(stderr, "ERROR: specify zip file name (only)\n"); 1296a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis goto bail; 130ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber } 131ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber zipFileName = bundle->getFileSpecEntry(0); 132ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber 1336a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis zip = openReadOnly(zipFileName); 134ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber if (zip == NULL) 1356a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis goto bail; 1366a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis 1376a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis int count, i; 1382163320110d2f971becbad82e15b2ab360a1ddb6Jamie Gennis 139593e2773f616a926af45e74359e21a898c89875fGlenn Kasten if (bundle->getVerbose()) { 140593e2773f616a926af45e74359e21a898c89875fGlenn Kasten printf("Archive: %s\n", zipFileName); 141593e2773f616a926af45e74359e21a898c89875fGlenn Kasten printf( 1426a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis " Length Method Size Ratio Date Time CRC-32 Name\n"); 1431e5b2b3361ddd07259bf4b29820ca4aa5f3a861bJamie Gennis printf( 1446a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis "-------- ------ ------- ----- ---- ---- ------ ----\n"); 14529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block } 1466a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis 1476a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis totalUncLen = totalCompLen = 0; 1486a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis 1496a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis count = zip->getNumEntries(); 1506a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis for (i = 0; i < count; i++) { 1516a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis entry = zip->getEntryByIndex(i); 1526a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis if (bundle->getVerbose()) { 1536a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis char dateBuf[32]; 1546a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis time_t when; 1556a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis 1566a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis when = entry->getModWhen(); 1576a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M", 1586a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis localtime(&when)); 1596a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis 160ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber printf("%8ld %-7.7s %7ld %3d%% %s %08lx %s\n", 161ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber (long) entry->getUncompressedLen(), 162ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber compressionName(entry->getCompressionMethod()), 163ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber (long) entry->getCompressedLen(), 164ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber calcPercent(entry->getUncompressedLen(), 165ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber entry->getCompressedLen()), 166ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber dateBuf, 167ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber entry->getCRC32(), 168ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber entry->getFileName()); 169ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber } else { 170ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber printf("%s\n", entry->getFileName()); 171ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber } 172ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber 173ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber totalUncLen += entry->getUncompressedLen(); 174ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber totalCompLen += entry->getCompressedLen(); 175ba529e486dde15fe75ea1b48570f9d60a4cf3c48Andreas Huber } 1766a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis 1776a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis if (bundle->getVerbose()) { 1786a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis printf( 1796a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis "-------- ------- --- -------\n"); 1806a9da9fc558263548ebfbae2cbf177eb7454a41bJamie Gennis printf("%8ld %7ld %2d%% %d files\n", 1817cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang totalUncLen, 1827cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang totalCompLen, 1837cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang calcPercent(totalUncLen, totalCompLen), 1847cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang zip->getNumEntries()); 1857cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang } 1867cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang 1877cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang if (bundle->getAndroidList()) { 1887cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang AssetManager assets; 1897cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang if (!assets.addAssetPath(String8(zipFileName), NULL)) { 190e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n"); 1917cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang goto bail; 192bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 1932e8ffaf95bd35358ecd14ddf00cddaf3abefe0a9Andreas Huber 1949b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber const ResTable& res = assets.getResources(false); 1952e8ffaf95bd35358ecd14ddf00cddaf3abefe0a9Andreas Huber if (&res == NULL) { 196c374dae535b83d9b499dd9fe8f9dabdb8b0ac9fdJames Dong printf("\nNo resource table found.\n"); 197fa090f541bb84a546af2ec834e91a032ff10e66eAndreas Huber } else { 198cbaffcffee6418d678806e63097c19fe26d48fe0Lajos Molnar printf("\nResource table:\n"); 199cbaffcffee6418d678806e63097c19fe26d48fe0Lajos Molnar res.print(); 200bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 201b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong 202b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml", 2034f6eed0d1c7972a983c075bdcf03089569e13fe1James Dong Asset::ACCESS_BUFFER); 204bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber if (manifestAsset == NULL) { 205acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber printf("\nNo AndroidManifest.xml found.\n"); 2067b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } else { 207150694cda0842d38a9358fe8d1fcb4fb4a76599eAndreas Huber printf("\nAndroid manifest:\n"); 2087a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3Gloria Wang ResXMLTree tree; 20994ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald tree.setTo(manifestAsset->getBuffer(true), 21094ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald manifestAsset->getLength()); 21194ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald printXMLBlock(&tree); 212e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber } 213bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber delete manifestAsset; 214bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 215bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 216c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber result = 0; 217bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 218c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huberbail: 219bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber delete zip; 220c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber return result; 22166b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber} 222145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber 223f90b123a3a67316284ba4b48a4fb0c5a36158545Sungsoo Limstatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes) 224c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber{ 225c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber size_t N = tree.getAttributeCount(); 226c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber for (size_t i=0; i<N; i++) { 227c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber if (tree.getAttributeNameResID(i) == attrRes) { 2281862a33b246249630b654182afb5914da3480d4cAndreas Huber return (ssize_t)i; 229bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 23094ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald } 23194ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald return -1; 23294ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald} 23394ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald 234bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huberstatic String8 getAttribute(const ResXMLTree& tree, const char* ns, 235bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber const char* attr, String8* outError) 236bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 237bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber ssize_t idx = tree.indexOfAttribute(ns, attr); 2382e8ffaf95bd35358ecd14ddf00cddaf3abefe0a9Andreas Huber if (idx < 0) { 2392e8ffaf95bd35358ecd14ddf00cddaf3abefe0a9Andreas Huber return String8(); 2402e8ffaf95bd35358ecd14ddf00cddaf3abefe0a9Andreas Huber } 241bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber Res_value value; 242bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 243bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (value.dataType != Res_value::TYPE_STRING) { 244bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (outError != NULL) *outError = "attribute is not a string value"; 245bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return String8(); 246bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 247c34233e673c9791e137456d0c427d58db184b690Andreas Huber } 248bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber size_t len; 249bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber const uint16_t* str = tree.getAttributeStringValue(idx, &len); 250145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber return str ? String8(str, len) : String8(); 251145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber} 25266b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber 25394ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgeraldstatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) 25494ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald{ 25594ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald ssize_t idx = indexOfAttribute(tree, attrRes); 25694ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald if (idx < 0) { 25794ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald return String8(); 258c34233e673c9791e137456d0c427d58db184b690Andreas Huber } 259c34233e673c9791e137456d0c427d58db184b690Andreas Huber Res_value value; 260c34233e673c9791e137456d0c427d58db184b690Andreas Huber if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 261c34233e673c9791e137456d0c427d58db184b690Andreas Huber if (value.dataType != Res_value::TYPE_STRING) { 262c34233e673c9791e137456d0c427d58db184b690Andreas Huber if (outError != NULL) *outError = "attribute is not a string value"; 263c34233e673c9791e137456d0c427d58db184b690Andreas Huber return String8(); 26466b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber } 26566b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber } 26642c5ae81036d4002da3fe1e3b1016131ba737e74Marco Nelissen size_t len; 26766b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber const uint16_t* str = tree.getAttributeStringValue(idx, &len); 268bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return str ? String8(str, len) : String8(); 269bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber} 2700726045216f576e97672ebeefc265d39c4ebaaa5Andreas Huber 271bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huberstatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError) 272bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 273bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber ssize_t idx = indexOfAttribute(tree, attrRes); 274bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (idx < 0) { 2759b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber return -1; 2763856b090cd04ba5dd4a59a12430ed724d5995909Steve Block } 2779b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber Res_value value; 2789b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 2799b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber if (value.dataType != Res_value::TYPE_INT_DEC) { 2809b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber if (outError != NULL) *outError = "attribute is not an integer value"; 2819b80c2bdb205bc143104f54d0743b6eedd67b14eAndreas Huber return -1; 2825561ccf4a8db88a2e44eac1b3ed13b4ff53a7f20Andreas Huber } 2831b86fe063badb5f28c467ade39be0f4008688947Andreas Huber } 2841b86fe063badb5f28c467ade39be0f4008688947Andreas Huber return value.data; 2851b86fe063badb5f28c467ade39be0f4008688947Andreas Huber} 286bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 2871b86fe063badb5f28c467ade39be0f4008688947Andreas Huberstatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree, 2887b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber uint32_t attrRes, String8* outError) 289bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 2907b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber ssize_t idx = indexOfAttribute(tree, attrRes); 2911b86fe063badb5f28c467ade39be0f4008688947Andreas Huber if (idx < 0) { 2921b86fe063badb5f28c467ade39be0f4008688947Andreas Huber return String8(); 2931b86fe063badb5f28c467ade39be0f4008688947Andreas Huber } 294bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber Res_value value; 295bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (tree.getAttributeValue(idx, &value) != NO_ERROR) { 2961b86fe063badb5f28c467ade39be0f4008688947Andreas Huber if (value.dataType == Res_value::TYPE_STRING) { 297bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber size_t len; 29866b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber const uint16_t* str = tree.getAttributeStringValue(idx, &len); 299bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber return str ? String8(str, len) : String8(); 300bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber } 3017314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber resTable->resolveReference(&value, 0); 3027314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber if (value.dataType != Res_value::TYPE_STRING) { 3037314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber if (outError != NULL) *outError = "attribute is not a string value"; 3047314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber return String8(); 3057314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber } 3067314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber } 3077314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber size_t len; 3087314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber const Res_value* value2 = &value; 309a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len); 3107314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber return str ? String8(str, len) : String8(); 3117314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber} 3127314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber 313a1df816c0677185534babba6ffc29970b048e52eLajos Molnar// These are attribute resource constants for the platform, as found 31466b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber// in android.R.attr 315bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huberenum { 316bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber NAME_ATTR = 0x01010003, 317bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber VERSION_CODE_ATTR = 0x0101021b, 31866b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber VERSION_NAME_ATTR = 0x0101021c, 319a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber LABEL_ATTR = 0x01010001, 320a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber ICON_ATTR = 0x01010002, 321a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber}; 322a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber 323a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber/* 324a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber * Handle the "dump" command, to extract select data from an archive. 325bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber */ 326bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huberint doDump(Bundle* bundle) 327bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber{ 328bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber status_t result = UNKNOWN_ERROR; 329bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber Asset* asset = NULL; 330bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 331bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (bundle->getFileSpecCount() < 1) { 332bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fprintf(stderr, "ERROR: no dump option specified\n"); 333bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return 1; 3347b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } 335bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 3367b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber if (bundle->getFileSpecCount() < 2) { 337bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fprintf(stderr, "ERROR: no dump file specified\n"); 338bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return 1; 339bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 340bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 341bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber const char* option = bundle->getFileSpecEntry(0); 3427b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber const char* filename = bundle->getFileSpecEntry(1); 3437b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber 344a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber AssetManager assets; 345a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber if (!assets.addAssetPath(String8(filename), NULL)) { 346a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n"); 347a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber return 1; 348a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 349a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber 3507b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber const ResTable& res = assets.getResources(false); 3517b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber if (&res == NULL) { 3527b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber fprintf(stderr, "ERROR: dump failed because no resource table was found\n"); 353e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber goto bail; 35485704836f33a199d7e442a23db82abbd5620d35dAndreas Huber } 355e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber 356e2b1028852120bcfded33b8f06f66b780437fe92Andreas Huber if (strcmp("resources", option) == 0) { 3577b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber res.print(); 3587b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber 3597b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } else if (strcmp("xmltree", option) == 0) { 360bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (bundle->getFileSpecCount() < 3) { 361bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 362bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber goto bail; 363bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 364bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 3659d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong for (int i=2; i<bundle->getFileSpecCount(); i++) { 3669d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong const char* resname = bundle->getFileSpecEntry(i); 3679d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong ResXMLTree tree; 3689d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 3699d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong if (asset == NULL) { 3709d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname); 3719d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong goto bail; 3729d2f386dd2885eaffa11fd494ae258bb09fe6397James Dong } 373785ee06d106cd7958e0c151ebc6b7174d9ba861eJames Dong 374785ee06d106cd7958e0c151ebc6b7174d9ba861eJames Dong if (tree.setTo(asset->getBuffer(true), 375785ee06d106cd7958e0c151ebc6b7174d9ba861eJames Dong asset->getLength()) != NO_ERROR) { 376785ee06d106cd7958e0c151ebc6b7174d9ba861eJames Dong fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 377785ee06d106cd7958e0c151ebc6b7174d9ba861eJames Dong goto bail; 3788f64134f749e4f7861a08a3063450fc714c4651dGloria Wang } 379dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang tree.restart(); 380bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber printXMLBlock(&tree); 381bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber delete asset; 382bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber asset = NULL; 3837fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 3847fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 3857fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } else if (strcmp("xmlstrings", option) == 0) { 3867fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber if (bundle->getFileSpecCount() < 3) { 3877fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber fprintf(stderr, "ERROR: no dump xmltree resource file specified\n"); 3887fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber goto bail; 389eec46abb88dcc50621fd2d3f17a6b8d24fd07a19James Dong } 3907fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 3917fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber for (int i=2; i<bundle->getFileSpecCount(); i++) { 3927fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber const char* resname = bundle->getFileSpecEntry(i); 3937fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber ResXMLTree tree; 3947fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); 395a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber if (asset == NULL) { 396a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname); 3973856b090cd04ba5dd4a59a12430ed724d5995909Steve Block goto bail; 398a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 3997fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 4007fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber if (tree.setTo(asset->getBuffer(true), 4017fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber asset->getLength()) != NO_ERROR) { 4027fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); 4037fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber goto bail; 4047fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 4057fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber printStringPool(&tree.getStrings()); 4067fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber delete asset; 4077fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber asset = NULL; 4083856b090cd04ba5dd4a59a12430ed724d5995909Steve Block } 4097fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 410a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } else { 411a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber ResXMLTree tree; 412a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber asset = assets.openNonAsset("AndroidManifest.xml", 413a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber Asset::ACCESS_BUFFER); 414a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber if (asset == NULL) { 415a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); 416a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber goto bail; 417a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 418bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 419bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (tree.setTo(asset->getBuffer(true), 420bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber asset->getLength()) != NO_ERROR) { 421bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); 422bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber goto bail; 42332bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber } 42432bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber tree.restart(); 425bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 42632bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber if (strcmp("permissions", option) == 0) { 42732bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber size_t len; 42832bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber ResXMLTree::event_code_t code; 42988d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber int depth = 0; 43088d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 431b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong if (code == ResXMLTree::END_TAG) { 432b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong depth--; 433b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong continue; 434b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong } 435b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong if (code != ResXMLTree::START_TAG) { 436b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong continue; 437b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong } 438b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong depth++; 439b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong String8 tag(tree.getElementName(&len)); 440b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong //printf("Depth %d tag %s\n", depth, tag.string()); 441b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong if (depth == 1) { 442b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong if (tag != "manifest") { 443a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 444a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber goto bail; 445a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 446a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber String8 pkg = getAttribute(tree, NULL, "package", NULL); 447a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber printf("package: %s\n", pkg.string()); 448a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } else if (depth == 2 && tag == "permission") { 44932bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber String8 error; 450a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber String8 name = getAttribute(tree, NAME_ATTR, &error); 45132bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber if (error != "") { 45288d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber fprintf(stderr, "ERROR: %s\n", error.string()); 45388d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber goto bail; 454ab7a2e544643edcb2e09ed5f204580afd763edc1James Dong } 4558ae49d87b98d57d6758b0c51b95e28a6581a79f1Andreas Huber printf("permission: %s\n", name.string()); 456a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } else if (depth == 2 && tag == "uses-permission") { 457a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber String8 error; 458a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber String8 name = getAttribute(tree, NAME_ATTR, &error); 459a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber if (error != "") { 460a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber fprintf(stderr, "ERROR: %s\n", error.string()); 461a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber goto bail; 46232bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber } 463a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber printf("uses-permission: %s\n", name.string()); 464a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 46532bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber } 4666954535ba64374e4e941cd83019a7af53edfb098Andreas Huber } else if (strcmp("badging", option) == 0) { 4676954535ba64374e4e941cd83019a7af53edfb098Andreas Huber size_t len; 4686954535ba64374e4e941cd83019a7af53edfb098Andreas Huber ResXMLTree::event_code_t code; 4696954535ba64374e4e941cd83019a7af53edfb098Andreas Huber int depth = 0; 4706954535ba64374e4e941cd83019a7af53edfb098Andreas Huber String8 error; 4716954535ba64374e4e941cd83019a7af53edfb098Andreas Huber bool withinActivity = false; 4726954535ba64374e4e941cd83019a7af53edfb098Andreas Huber bool isMainActivity = false; 4736954535ba64374e4e941cd83019a7af53edfb098Andreas Huber bool isLauncherActivity = false; 474a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber String8 activityName; 4756954535ba64374e4e941cd83019a7af53edfb098Andreas Huber String8 activityLabel; 4768ae49d87b98d57d6758b0c51b95e28a6581a79f1Andreas Huber String8 activityIcon; 47732bdfd5acb76a02e82e0059c8bd892bc1f73a7e3Andreas Huber while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { 4786a3969cc3bcbfc84dbcc27aa726eb96bc03a830bEdwin Wong if (code == ResXMLTree::END_TAG) { 479bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber depth--; 480bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber continue; 481bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 482acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber if (code != ResXMLTree::START_TAG) { 4838a74c9b8e2627560ae5a92d4261f0de4464490adEdwin Wong continue; 4848a74c9b8e2627560ae5a92d4261f0de4464490adEdwin Wong } 4858a74c9b8e2627560ae5a92d4261f0de4464490adEdwin Wong depth++; 4868a74c9b8e2627560ae5a92d4261f0de4464490adEdwin Wong String8 tag(tree.getElementName(&len)); 4878a74c9b8e2627560ae5a92d4261f0de4464490adEdwin Wong //printf("Depth %d tag %s\n", depth, tag.string()); 488acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber if (depth == 1) { 489acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber if (tag != "manifest") { 490acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n"); 491acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber goto bail; 492acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber } 493bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber String8 pkg = getAttribute(tree, NULL, "package", NULL); 494bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber printf("package: name='%s' ", pkg.string()); 495bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error); 496bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (error != "") { 497bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string()); 498bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber goto bail; 499bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 500bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (versionCode > 0) { 501c374dae535b83d9b499dd9fe8f9dabdb8b0ac9fdJames Dong printf("versionCode='%d' ", versionCode); 502ab7a2e544643edcb2e09ed5f204580afd763edc1James Dong } else { 503b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong printf("versionCode='' "); 504b45c01c2b8588ff431b511151666a55a39f0a6aeJames Dong } 50565a170e3ac593a29abd0c76e9aa531fabad7f56dAndreas Huber String8 versionName = getAttribute(tree, VERSION_NAME_ATTR, &error); 506cbaffcffee6418d678806e63097c19fe26d48fe0Lajos Molnar if (error != "") { 507cbaffcffee6418d678806e63097c19fe26d48fe0Lajos Molnar fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string()); 508dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang goto bail; 509dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang } 510dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang printf("versionName='%s'\n", versionName.string()); 511dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang } else if (depth == 2 && tag == "application") { 512dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang String8 label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 513dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang if (error != "") { 514dcd25efb46c41c8d24a0a9cf61fb57f84149709eGloria Wang fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); 5157cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang goto bail; 5167cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang } 5177cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang printf("application: label='%s' ", label.string()); 5187cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang 5197cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 5207cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang if (error != "") { 5217cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 5227cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang goto bail; 5237cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang } 5247cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang printf("icon='%s'\n", icon.string()); 5257cf180c9bff69e5cc4a2f4e53b432db45ebbebabGloria Wang } else if (depth == 3 && tag == "activity") { 526e94bd14078d327ef2f800e69907efce641a13272Andreas Huber withinActivity = true; 527a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber //printf("LOG: withinActivity==true\n"); 528e94bd14078d327ef2f800e69907efce641a13272Andreas Huber 529df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block activityName = getAttribute(tree, NAME_ATTR, &error); 530e94bd14078d327ef2f800e69907efce641a13272Andreas Huber if (error != "") { 531e94bd14078d327ef2f800e69907efce641a13272Andreas Huber fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 5326a05c9e912aeb8bfe1ef99516def91a177a481b6Andreas Huber goto bail; 5336a05c9e912aeb8bfe1ef99516def91a177a481b6Andreas Huber } 5346a05c9e912aeb8bfe1ef99516def91a177a481b6Andreas Huber 5356a05c9e912aeb8bfe1ef99516def91a177a481b6Andreas Huber activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error); 5366a05c9e912aeb8bfe1ef99516def91a177a481b6Andreas Huber if (error != "") { 5376a05c9e912aeb8bfe1ef99516def91a177a481b6Andreas Huber fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string()); 538e94bd14078d327ef2f800e69907efce641a13272Andreas Huber goto bail; 539e94bd14078d327ef2f800e69907efce641a13272Andreas Huber } 540bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber 541bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error); 542bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber if (error != "") { 543bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string()); 544bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber goto bail; 545bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 546681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } else if (depth == 5 && withinActivity) { 5470a5baa9b411fe086013d2a5e9126ed63fbad046cAndreas Huber if (tag == "action") { 54888d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber //printf("LOG: action tag\n"); 54988d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber String8 action = getAttribute(tree, NAME_ATTR, &error); 550eec46abb88dcc50621fd2d3f17a6b8d24fd07a19James Dong if (error != "") { 55188d8a83de12592635248aa1a3bd6b9ea46108501Andreas Huber fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string()); 55294ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald goto bail; 5537b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } 5547b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber if (action == "android.intent.action.MAIN") { 5557b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber isMainActivity = true; 5567b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber //printf("LOG: isMainActivity==true\n"); 5575b75fdc8fbc026453888cbb2d3fe31345394618bGloria Wang } 5585b75fdc8fbc026453888cbb2d3fe31345394618bGloria Wang } else if (tag == "category") { 559e94bd14078d327ef2f800e69907efce641a13272Andreas Huber String8 category = getAttribute(tree, NAME_ATTR, &error); 560e94bd14078d327ef2f800e69907efce641a13272Andreas Huber if (error != "") { 561e94bd14078d327ef2f800e69907efce641a13272Andreas Huber fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string()); 562e94bd14078d327ef2f800e69907efce641a13272Andreas Huber goto bail; 563e94bd14078d327ef2f800e69907efce641a13272Andreas Huber } 5647b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber if (category == "android.intent.category.LAUNCHER") { 56594ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald isLauncherActivity = true; 5667b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber //printf("LOG: isLauncherActivity==true\n"); 5677b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } 5687b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } 5697b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } 5707b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber 5717b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber if (depth < 3) { 5726655174826330afe66ef766258181ae8c11f3f6cInsun Kang //if (withinActivity) printf("LOG: withinActivity==false\n"); 5736655174826330afe66ef766258181ae8c11f3f6cInsun Kang withinActivity = false; 5746655174826330afe66ef766258181ae8c11f3f6cInsun Kang } 5757a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3Gloria Wang 5767a1e3e81264189e23a1db2b174e1b5a5d4c7d1c3Gloria Wang if (depth < 5) { 577b9280d5c2313c41eb490f58198c4e59118e0e3e6Andreas Huber //if (isMainActivity) printf("LOG: isMainActivity==false\n"); 578b9280d5c2313c41eb490f58198c4e59118e0e3e6Andreas Huber //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n"); 579bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber isMainActivity = false; 580150694cda0842d38a9358fe8d1fcb4fb4a76599eAndreas Huber isLauncherActivity = false; 581bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 582bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 583bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (withinActivity && isMainActivity && isLauncherActivity) { 584a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber printf("launchable activity: name='%s' label='%s' icon='%s'\n", 585acdd9d0f59c3d8bdc3de80664a609527ec3d21e2Andreas Huber activityName.string(), activityLabel.string(), 586bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber activityIcon.string()); 587bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 588bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 58964bb6983690bf994d904591145a3cdd6373bdbe6Andreas Huber printf("locales:"); 590af64a8a6ad89f52685e822dca30742a4132c9ae6Gloria Wang Vector<String8> locales; 591bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber res.getLocales(&locales); 59266b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber const size_t N = locales.size(); 5931b86fe063badb5f28c467ade39be0f4008688947Andreas Huber for (size_t i=0; i<N; i++) { 594bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber const char* localeStr = locales[i].string(); 595bd22c52280179b29eefac91ef7e7bbbc33d25904Andreas Huber if (localeStr == NULL || strlen(localeStr) == 0) { 5967b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber localeStr = "--_--"; 5977b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber } 5987b3396acc702451be9bafb19d7fe26d55d43a316Andreas Huber printf(" '%s'", localeStr); 5997fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 600150694cda0842d38a9358fe8d1fcb4fb4a76599eAndreas Huber printf("\n"); 601a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } else if (strcmp("configurations", option) == 0) { 602a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber Vector<ResTable_config> configs; 603a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber res.getConfigurations(&configs); 604a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber const size_t N = configs.size(); 605a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber for (size_t i=0; i<N; i++) { 606a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber printf("%s\n", configs[i].toString().string()); 607a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 608a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } else { 609a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber fprintf(stderr, "ERROR: unknown dump option '%s'\n", option); 610a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber goto bail; 611a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 612a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 613a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber 614a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber result = NO_ERROR; 615a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber 616a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huberbail: 61799590d29c9d3081cadfccd036842f5ce9a7debefAndreas Huber if (asset) { 61899590d29c9d3081cadfccd036842f5ce9a7debefAndreas Huber delete asset; 619f4909f67d8be28e3b0a5e9429479b102773b2ea8Lajos Molnar } 620f4909f67d8be28e3b0a5e9429479b102773b2ea8Lajos Molnar return (result != NO_ERROR); 621f4909f67d8be28e3b0a5e9429479b102773b2ea8Lajos Molnar} 622bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 623bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber 624c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber/* 62594ea60f975c3eb7ce6d2a4430538a42a5fc3babdRichard Fitzgerald * Handle the "add" command, which wants to add files to a new or 6260726045216f576e97672ebeefc265d39c4ebaaa5Andreas Huber * pre-existing archive. 6270726045216f576e97672ebeefc265d39c4ebaaa5Andreas Huber */ 6280726045216f576e97672ebeefc265d39c4ebaaa5Andreas Huberint doAdd(Bundle* bundle) 629c23f12af0394aa2f6651968a3c8840f1af317aa1Andreas Huber{ 63066b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber ZipFile* zip = NULL; 63166b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber status_t result = UNKNOWN_ERROR; 63266b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber const char* zipFileName; 63366b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber 6347fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber if (bundle->getUpdate()) { 635c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong /* avoid confusion */ 636776a0023f5146423e88474c35691eb0e20fc8102Ajay Dudani fprintf(stderr, "ERROR: can't use '-u' with add\n"); 6377fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber goto bail; 6387fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 6397fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 6407fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber if (bundle->getFileSpecCount() < 1) { 6417fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber fprintf(stderr, "ERROR: must specify zip file name\n"); 6427fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber goto bail; 6437fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 6447fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber zipFileName = bundle->getFileSpecEntry(0); 6457fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 6467fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber if (bundle->getFileSpecCount() < 2) { 6477fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber fprintf(stderr, "NOTE: nothing to do\n"); 6487fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber goto bail; 6497fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 6507fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber 6517fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber zip = openReadWrite(zipFileName, true); 6528650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (zip == NULL) { 6538650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName); 6547fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber goto bail; 6558650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber } 656b9b8d14d89019ba7b9d183f0fbad2af924a0cd95hovanchen 6571bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney for (int i = 1; i < bundle->getFileSpecCount(); i++) { 6581bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney const char* fileName = bundle->getFileSpecEntry(i); 6598650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber 6601bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) { 6618650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber printf(" '%s'... (from gzip)\n", fileName); 662681755fc0d0797506456f46a2a10555916d6be32Andreas Huber result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL); 663681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } else { 664681755fc0d0797506456f46a2a10555916d6be32Andreas Huber printf(" '%s'...\n", fileName); 665681755fc0d0797506456f46a2a10555916d6be32Andreas Huber result = zip->add(fileName, bundle->getCompressionMethod(), NULL); 666681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } 6678650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (result != NO_ERROR) { 6688650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName); 6698650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (result == NAME_NOT_FOUND) 6708650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber fprintf(stderr, ": file not found\n"); 6718650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber else if (result == ALREADY_EXISTS) 67234ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber fprintf(stderr, ": already exists in archive\n"); 67334ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber else 67434ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber fprintf(stderr, "\n"); 67534ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber goto bail; 67634ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber } 67734ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber } 678145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber 679145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber result = NO_ERROR; 680145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber 681145e68fc778275963189b02a1adcbe27cce4d769Andreas Huberbail: 682145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber delete zip; 683145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber return (result != NO_ERROR); 684145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber} 685145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber 686145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber 687145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber/* 6885dac87b088556b8ed7f2a4f5546d31be0bb68680Andreas Huber * Delete files from an existing archive. 6893856b090cd04ba5dd4a59a12430ed724d5995909Steve Block */ 690145e68fc778275963189b02a1adcbe27cce4d769Andreas Huberint doRemove(Bundle* bundle) 691145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber{ 692145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber ZipFile* zip = NULL; 693145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber status_t result = UNKNOWN_ERROR; 694145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber const char* zipFileName; 695145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber 696145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber if (bundle->getFileSpecCount() < 1) { 697145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber fprintf(stderr, "ERROR: must specify zip file name\n"); 698145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber goto bail; 699145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber } 70066b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber zipFileName = bundle->getFileSpecEntry(0); 70166b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber 702d29345dfa29cdcc650f3705e43950ef2500f6728Andreas Huber if (bundle->getFileSpecCount() < 2) { 703d29345dfa29cdcc650f3705e43950ef2500f6728Andreas Huber fprintf(stderr, "NOTE: nothing to do\n"); 704d29345dfa29cdcc650f3705e43950ef2500f6728Andreas Huber goto bail; 70566b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber } 70666b0a35c9a4136a84c3f73b1b25fcb5220138b95Andreas Huber 7078650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber zip = openReadWrite(zipFileName, false); 7081bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney if (zip == NULL) { 7091bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n", 7101bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney zipFileName); 711c9e894872c298b25fe9d74e68aa1e7287a541ac3Andreas Huber goto bail; 7128650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber } 7131bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney 7141bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney for (int i = 1; i < bundle->getFileSpecCount(); i++) { 7151bd233ce7e1aa7730bc18d46ffd57791391738cdBryan Mawhinney const char* fileName = bundle->getFileSpecEntry(i); 71683977eb230d829cfe520f55d7977037a904ce548Andreas Huber ZipEntry* entry; 7173856b090cd04ba5dd4a59a12430ed724d5995909Steve Block 71883977eb230d829cfe520f55d7977037a904ce548Andreas Huber entry = zip->getEntryByName(fileName); 71983977eb230d829cfe520f55d7977037a904ce548Andreas Huber if (entry == NULL) { 7208650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber printf(" '%s' NOT FOUND\n", fileName); 7217fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber continue; 7227fbdb0903dfbf70b314a74e64e28fb880cdb9247Andreas Huber } 7238650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber 7248650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber result = zip->remove(entry); 725c9e894872c298b25fe9d74e68aa1e7287a541ac3Andreas Huber 7268650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (result != NO_ERROR) { 7278650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber fprintf(stderr, "Unable to delete '%s' from '%s'\n", 7288650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber bundle->getFileSpecEntry(i), zipFileName); 7298650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber goto bail; 730c9e894872c298b25fe9d74e68aa1e7287a541ac3Andreas Huber } 7318650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber } 7328650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber 7338650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber /* update the archive */ 7348650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber zip->flush(); 7358650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber 7368650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huberbail: 7378650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber delete zip; 738377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT return (result != NO_ERROR); 7398650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber} 740a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber 7418650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber 74234ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber/* 7435b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong * Package up an asset directory and associated application files. 7448650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber */ 7458650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huberint doPackage(Bundle* bundle) 7468650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber{ 747377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT const char* outputAPKFile; 7488650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber int retVal = 1; 749a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber status_t err; 7508650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber sp<AaptAssets> assets; 7518650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber int N; 752377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT 7538650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber // -c zz_ZZ means do pseudolocalization 7548650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber ResourceFilter filter; 7558650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber err = filter.parse(bundle->getConfigurations()); 7568650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (err != NO_ERROR) { 7578650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber goto bail; 7588650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber } 759681755fc0d0797506456f46a2a10555916d6be32Andreas Huber if (filter.containsPseudo()) { 760681755fc0d0797506456f46a2a10555916d6be32Andreas Huber bundle->setPseudolocalize(true); 761681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } 762681755fc0d0797506456f46a2a10555916d6be32Andreas Huber 763681755fc0d0797506456f46a2a10555916d6be32Andreas Huber N = bundle->getFileSpecCount(); 764681755fc0d0797506456f46a2a10555916d6be32Andreas Huber if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0 765681755fc0d0797506456f46a2a10555916d6be32Andreas Huber && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) { 766681755fc0d0797506456f46a2a10555916d6be32Andreas Huber fprintf(stderr, "ERROR: no input files\n"); 767681755fc0d0797506456f46a2a10555916d6be32Andreas Huber goto bail; 768681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } 769681755fc0d0797506456f46a2a10555916d6be32Andreas Huber 770681755fc0d0797506456f46a2a10555916d6be32Andreas Huber outputAPKFile = bundle->getOutputAPKFile(); 771681755fc0d0797506456f46a2a10555916d6be32Andreas Huber 7723856b090cd04ba5dd4a59a12430ed724d5995909Steve Block // Make sure the filenames provided exist and are of the appropriate type. 773681755fc0d0797506456f46a2a10555916d6be32Andreas Huber if (outputAPKFile) { 774681755fc0d0797506456f46a2a10555916d6be32Andreas Huber FileType type; 775681755fc0d0797506456f46a2a10555916d6be32Andreas Huber type = getFileType(outputAPKFile); 776681755fc0d0797506456f46a2a10555916d6be32Andreas Huber if (type != kFileTypeNonexistent && type != kFileTypeRegular) { 777681755fc0d0797506456f46a2a10555916d6be32Andreas Huber fprintf(stderr, 778681755fc0d0797506456f46a2a10555916d6be32Andreas Huber "ERROR: output file '%s' exists but is not regular file\n", 779681755fc0d0797506456f46a2a10555916d6be32Andreas Huber outputAPKFile); 780681755fc0d0797506456f46a2a10555916d6be32Andreas Huber goto bail; 781681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } 782681755fc0d0797506456f46a2a10555916d6be32Andreas Huber } 7832415ecb5bb4e1459024f6d6c8ae2d6e3dc4fbdc7Andreas Huber 7842415ecb5bb4e1459024f6d6c8ae2d6e3dc4fbdc7Andreas Huber // Load the assets. 7858650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber assets = new AaptAssets(); 7862a4b49bd3863024884a694b454e2e452752e6ea0Andreas Huber err = assets->slurpFromArgs(bundle); 7878650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (err < 0) { 7883856b090cd04ba5dd4a59a12430ed724d5995909Steve Block goto bail; 78934ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber } 79034ef0f32c8fc0186236a27e07405328cc1f7c56dAndreas Huber 7918650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber if (bundle->getVerbose()) { 7928650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber assets->print(); 793a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber } 794a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker 795a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker // If they asked for any files that need to be compiled, do so. 796a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) { 797a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker err = buildResources(bundle, assets); 798f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker if (err != 0) { 7998650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber goto bail; 8002bfdd428c56c7524d1a11979f200a1762866032dAndreas Huber } 8018650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber } 802a0b1d4b161599c2bb2a47119e50c51e75bbe980eAndreas Huber 803a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker // At this point we've read everything and processed everything. From here 804a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker // on out it's just writing output files. 805a3fafcb4ee6d6344f2b5b602d095a4ffebc8dbb7Jeff Tinker if (SourcePos::hasErrors()) { 8068650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber goto bail; 8073856b090cd04ba5dd4a59a12430ed724d5995909Steve Block } 8088650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber 8098650e1960905097f6f1d6aa462ccb1c93c656834Andreas Huber // Write out R.java constants 8102a4b49bd3863024884a694b454e2e452752e6ea0Andreas Huber if (assets->getPackage() == assets->getSymbolsPrivatePackage()) { 8112a4b49bd3863024884a694b454e2e452752e6ea0Andreas Huber err = writeResourceSymbols(bundle, assets, assets->getPackage(), true); 8120a5baa9b411fe086013d2a5e9126ed63fbad046cAndreas Huber if (err < 0) { 8130a5baa9b411fe086013d2a5e9126ed63fbad046cAndreas Huber goto bail; 8146fa20187e4cf9ace5692979a84741484f19e3f57Andreas Huber } 815aab5b08cb4a3b5a47daece6168f41ec918020739Eric Laurent } else { 816aab5b08cb4a3b5a47daece6168f41ec918020739Eric Laurent err = writeResourceSymbols(bundle, assets, assets->getPackage(), false); 8170726045216f576e97672ebeefc265d39c4ebaaa5Andreas Huber if (err < 0) { 8180726045216f576e97672ebeefc265d39c4ebaaa5Andreas Huber goto bail; 8195b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong } 8205b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true); 821f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker if (err < 0) { 8225b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong goto bail; 823f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker } 824f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker } 825f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker 826f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker // Write the apk 827f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker if (outputAPKFile) { 828f10f36d34812bae602ff018fb503ad07eaf550b1Jeffrey Tinker err = writeAPK(bundle, assets, String8(outputAPKFile)); 8295b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong if (err != NO_ERROR) { 8305b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile); 8315b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong goto bail; 8325b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong } 8335b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong } 8345b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong 8355b1b8a93a07326f1cbc627f09e02988375189e0aJames Dong retVal = 0; 836bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huberbail: 837bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber if (SourcePos::hasErrors()) { 8382163320110d2f971becbad82e15b2ab360a1ddb6Jamie Gennis SourcePos::printErrors(stderr); 839bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber } 840bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber return retVal; 841d29345dfa29cdcc650f3705e43950ef2500f6728Andreas Huber} 842d29345dfa29cdcc650f3705e43950ef2500f6728Andreas Huber