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