Command.cpp revision 6919f69281e32d0c3d4b3791b273f71f178cbb7c
15778822d86b0337407514b9372562b86edfa91cdAndreas Huber//
25778822d86b0337407514b9372562b86edfa91cdAndreas Huber// Copyright 2006 The Android Open Source Project
35778822d86b0337407514b9372562b86edfa91cdAndreas Huber//
45778822d86b0337407514b9372562b86edfa91cdAndreas Huber// Android Asset Packaging Tool main entry point.
55778822d86b0337407514b9372562b86edfa91cdAndreas Huber//
65778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include "Main.h"
75778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include "Bundle.h"
85778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include "ResourceTable.h"
95778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include "XMLNode.h"
105778822d86b0337407514b9372562b86edfa91cdAndreas Huber
115778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <utils/Log.h>
125778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <utils/threads.h>
135778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <utils/List.h>
145778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <utils/Errors.h>
155778822d86b0337407514b9372562b86edfa91cdAndreas Huber
165778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <fcntl.h>
175778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <errno.h>
185778822d86b0337407514b9372562b86edfa91cdAndreas Huber
195778822d86b0337407514b9372562b86edfa91cdAndreas Huberusing namespace android;
205778822d86b0337407514b9372562b86edfa91cdAndreas Huber
215778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
225778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Show version info.  All the cool kids do it.
235778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
245778822d86b0337407514b9372562b86edfa91cdAndreas Huberint doVersion(Bundle* bundle)
251a2952aee048ca7b1765e2bc09ebe9aeddaeafa3Mathias Agopian{
26ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber    if (bundle->getFileSpecCount() != 0)
275778822d86b0337407514b9372562b86edfa91cdAndreas Huber        printf("(ignoring extra arguments)\n");
285778822d86b0337407514b9372562b86edfa91cdAndreas Huber    printf("Android Asset Packaging Tool, v0.2\n");
295778822d86b0337407514b9372562b86edfa91cdAndreas Huber
305b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber    return 0;
31ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber}
325778822d86b0337407514b9372562b86edfa91cdAndreas Huber
337cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
345778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
355778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Open the file read only.  The call fails if the file doesn't exist.
365778822d86b0337407514b9372562b86edfa91cdAndreas Huber *
375778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Returns NULL on failure.
385778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
395778822d86b0337407514b9372562b86edfa91cdAndreas HuberZipFile* openReadOnly(const char* fileName)
405778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
415778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ZipFile* zip;
425778822d86b0337407514b9372562b86edfa91cdAndreas Huber    status_t result;
435778822d86b0337407514b9372562b86edfa91cdAndreas Huber
445778822d86b0337407514b9372562b86edfa91cdAndreas Huber    zip = new ZipFile;
455778822d86b0337407514b9372562b86edfa91cdAndreas Huber    result = zip->open(fileName, ZipFile::kOpenReadOnly);
465778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (result != NO_ERROR) {
475778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (result == NAME_NOT_FOUND)
485778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
495778822d86b0337407514b9372562b86edfa91cdAndreas Huber        else if (result == PERMISSION_DENIED)
505778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
515778822d86b0337407514b9372562b86edfa91cdAndreas Huber        else
525778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
535778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fileName);
545778822d86b0337407514b9372562b86edfa91cdAndreas Huber        delete zip;
555778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return NULL;
565778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
575778822d86b0337407514b9372562b86edfa91cdAndreas Huber
585778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return zip;
595778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
605778822d86b0337407514b9372562b86edfa91cdAndreas Huber
615778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
625778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Open the file read-write.  The file will be created if it doesn't
635778822d86b0337407514b9372562b86edfa91cdAndreas Huber * already exist and "okayToCreate" is set.
645778822d86b0337407514b9372562b86edfa91cdAndreas Huber *
655778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Returns NULL on failure.
667cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden */
675778822d86b0337407514b9372562b86edfa91cdAndreas HuberZipFile* openReadWrite(const char* fileName, bool okayToCreate)
685778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
695778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ZipFile* zip = NULL;
705778822d86b0337407514b9372562b86edfa91cdAndreas Huber    status_t result;
715778822d86b0337407514b9372562b86edfa91cdAndreas Huber    int flags;
726507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden
736507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden    flags = ZipFile::kOpenReadWrite;
745778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (okayToCreate)
755778822d86b0337407514b9372562b86edfa91cdAndreas Huber        flags |= ZipFile::kOpenCreate;
765778822d86b0337407514b9372562b86edfa91cdAndreas Huber
775778822d86b0337407514b9372562b86edfa91cdAndreas Huber    zip = new ZipFile;
785778822d86b0337407514b9372562b86edfa91cdAndreas Huber    result = zip->open(fileName, flags);
795778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (result != NO_ERROR) {
805778822d86b0337407514b9372562b86edfa91cdAndreas Huber        delete zip;
815778822d86b0337407514b9372562b86edfa91cdAndreas Huber        zip = NULL;
825778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
835778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
845778822d86b0337407514b9372562b86edfa91cdAndreas Huber
855778822d86b0337407514b9372562b86edfa91cdAndreas Huberbail:
865778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return zip;
875778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
885778822d86b0337407514b9372562b86edfa91cdAndreas Huber
895778822d86b0337407514b9372562b86edfa91cdAndreas Huber
905778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
915778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Return a short string describing the compression method.
925778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
935778822d86b0337407514b9372562b86edfa91cdAndreas Huberconst char* compressionName(int method)
945778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
955778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (method == ZipEntry::kCompressStored)
965778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return "Stored";
975778822d86b0337407514b9372562b86edfa91cdAndreas Huber    else if (method == ZipEntry::kCompressDeflated)
985778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return "Deflated";
995778822d86b0337407514b9372562b86edfa91cdAndreas Huber    else
1005778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return "Unknown";
1015778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
1025778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1035778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
1045778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Return the percent reduction in size (0% == no compression).
1055778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
1065778822d86b0337407514b9372562b86edfa91cdAndreas Huberint calcPercent(long uncompressedLen, long compressedLen)
1075778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
1085778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (!uncompressedLen)
1095778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return 0;
1105778822d86b0337407514b9372562b86edfa91cdAndreas Huber    else
1115778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
1125778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
1135778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1145778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
1155778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Handle the "list" command, which can be a simple file dump or
1165778822d86b0337407514b9372562b86edfa91cdAndreas Huber * a verbose listing.
1175778822d86b0337407514b9372562b86edfa91cdAndreas Huber *
1185778822d86b0337407514b9372562b86edfa91cdAndreas Huber * The verbose listing closely matches the output of the Info-ZIP "unzip"
1195778822d86b0337407514b9372562b86edfa91cdAndreas Huber * command.
1205778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
1215778822d86b0337407514b9372562b86edfa91cdAndreas Huberint doList(Bundle* bundle)
1225778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
1235778822d86b0337407514b9372562b86edfa91cdAndreas Huber    int result = 1;
1245778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ZipFile* zip = NULL;
1255778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const ZipEntry* entry;
1265778822d86b0337407514b9372562b86edfa91cdAndreas Huber    long totalUncLen, totalCompLen;
1275778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char* zipFileName;
1285778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1295778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getFileSpecCount() != 1) {
1305778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: specify zip file name (only)\n");
1315778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
1325778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
1335778822d86b0337407514b9372562b86edfa91cdAndreas Huber    zipFileName = bundle->getFileSpecEntry(0);
1345778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1355778822d86b0337407514b9372562b86edfa91cdAndreas Huber    zip = openReadOnly(zipFileName);
1365778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (zip == NULL)
1375778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
1381a2952aee048ca7b1765e2bc09ebe9aeddaeafa3Mathias Agopian
1391bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    int count, i;
1405778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1415778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getVerbose()) {
1425778822d86b0337407514b9372562b86edfa91cdAndreas Huber        printf("Archive:  %s\n", zipFileName);
1435778822d86b0337407514b9372562b86edfa91cdAndreas Huber        printf(
1445778822d86b0337407514b9372562b86edfa91cdAndreas Huber            " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n");
1455778822d86b0337407514b9372562b86edfa91cdAndreas Huber        printf(
1465778822d86b0337407514b9372562b86edfa91cdAndreas Huber            "--------  ------  ------- -----   ----   ----   ------    ----\n");
1471bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    }
1481bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber
1491bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    totalUncLen = totalCompLen = 0;
1501bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber
1511bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    count = zip->getNumEntries();
1521bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    for (i = 0; i < count; i++) {
1531bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber        entry = zip->getEntryByIndex(i);
1545778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (bundle->getVerbose()) {
1555778822d86b0337407514b9372562b86edfa91cdAndreas Huber            char dateBuf[32];
1565778822d86b0337407514b9372562b86edfa91cdAndreas Huber            time_t when;
1575778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1585778822d86b0337407514b9372562b86edfa91cdAndreas Huber            when = entry->getModWhen();
1595778822d86b0337407514b9372562b86edfa91cdAndreas Huber            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
1607cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                localtime(&when));
1617cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
1627cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden            printf("%8ld  %-7.7s %7ld %3d%%  %s  %08lx  %s\n",
1637cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                (long) entry->getUncompressedLen(),
1647cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                compressionName(entry->getCompressionMethod()),
1657cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                (long) entry->getCompressedLen(),
1667cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                calcPercent(entry->getUncompressedLen(),
1677cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                            entry->getCompressedLen()),
1687cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                dateBuf,
1697cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                entry->getCRC32(),
1707cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                entry->getFileName());
1717cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden        } else {
1727cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden            printf("%s\n", entry->getFileName());
1737cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden        }
1747cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
1757cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden        totalUncLen += entry->getUncompressedLen();
1767cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden        totalCompLen += entry->getCompressedLen();
1777cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    }
1787cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
1797cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    if (bundle->getVerbose()) {
1805778822d86b0337407514b9372562b86edfa91cdAndreas Huber        printf(
1815778822d86b0337407514b9372562b86edfa91cdAndreas Huber        "--------          -------  ---                            -------\n");
1825778822d86b0337407514b9372562b86edfa91cdAndreas Huber        printf("%8ld          %7ld  %2d%%                            %d files\n",
1835778822d86b0337407514b9372562b86edfa91cdAndreas Huber            totalUncLen,
1845778822d86b0337407514b9372562b86edfa91cdAndreas Huber            totalCompLen,
1855778822d86b0337407514b9372562b86edfa91cdAndreas Huber            calcPercent(totalUncLen, totalCompLen),
1865778822d86b0337407514b9372562b86edfa91cdAndreas Huber            zip->getNumEntries());
1875778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
1885778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1895778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getAndroidList()) {
1905778822d86b0337407514b9372562b86edfa91cdAndreas Huber        AssetManager assets;
1915778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
1925778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
1935778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
194c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        }
195c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber
196c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        const ResTable& res = assets.getResources(false);
197c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        if (&res == NULL) {
198c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            printf("\nNo resource table found.\n");
199c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        } else {
200c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            printf("\nResource table:\n");
2015778822d86b0337407514b9372562b86edfa91cdAndreas Huber            res.print(false);
2025778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2035778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2045778822d86b0337407514b9372562b86edfa91cdAndreas Huber        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
2055778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                                   Asset::ACCESS_BUFFER);
2065b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber        if (manifestAsset == NULL) {
2075b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber            printf("\nNo AndroidManifest.xml found.\n");
2085b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber        } else {
2095b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber            printf("\nAndroid manifest:\n");
2105b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber            ResXMLTree tree;
2115b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber            tree.setTo(manifestAsset->getBuffer(true),
2125778822d86b0337407514b9372562b86edfa91cdAndreas Huber                       manifestAsset->getLength());
2135778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printXMLBlock(&tree);
2145778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2155778822d86b0337407514b9372562b86edfa91cdAndreas Huber        delete manifestAsset;
2165778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
2175778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2185b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber    result = 0;
2195778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2205778822d86b0337407514b9372562b86edfa91cdAndreas Huberbail:
2215778822d86b0337407514b9372562b86edfa91cdAndreas Huber    delete zip;
2225778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return result;
2235778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
2244b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber
2254b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huberstatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
2264b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber{
2274b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    size_t N = tree.getAttributeCount();
2284b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    for (size_t i=0; i<N; i++) {
2294b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber        if (tree.getAttributeNameResID(i) == attrRes) {
2304b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber            return (ssize_t)i;
2314b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber        }
2324b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    }
2335b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber    return -1;
2345b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber}
2355b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber
2365b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huberstatic String8 getAttribute(const ResXMLTree& tree, const char* ns,
2375b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber                            const char* attr, String8* outError)
2385b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber{
2394b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    ssize_t idx = tree.indexOfAttribute(ns, attr);
2404b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    if (idx < 0) {
2414b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber        return String8();
2424b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    }
2434b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    Res_value value;
2444b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
2454b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber        if (value.dataType != Res_value::TYPE_STRING) {
2464b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber            if (outError != NULL) *outError = "attribute is not a string value";
2474b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber            return String8();
2484b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber        }
2495b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber    }
2504b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    size_t len;
2514b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
2525b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber    return str ? String8(str, len) : String8();
2535b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber}
2545b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber
2554b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huberstatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
2564b75a9c8b93a90749bc5d22912ad0d96c12f4ecfAndreas Huber{
2575778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ssize_t idx = indexOfAttribute(tree, attrRes);
2585778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (idx < 0) {
2595778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return String8();
2605778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
2615778822d86b0337407514b9372562b86edfa91cdAndreas Huber    Res_value value;
2625778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
2635778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (value.dataType != Res_value::TYPE_STRING) {
2645778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (outError != NULL) *outError = "attribute is not a string value";
2655778822d86b0337407514b9372562b86edfa91cdAndreas Huber            return String8();
2665778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2675778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
2685778822d86b0337407514b9372562b86edfa91cdAndreas Huber    size_t len;
2695778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
2705778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return str ? String8(str, len) : String8();
2715778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
2725778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2735778822d86b0337407514b9372562b86edfa91cdAndreas Huberstatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
2745778822d86b0337407514b9372562b86edfa91cdAndreas Huber        String8* outError, int32_t defValue = -1)
2755778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
2765778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ssize_t idx = indexOfAttribute(tree, attrRes);
2775778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (idx < 0) {
2785778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return defValue;
2795778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
2805778822d86b0337407514b9372562b86edfa91cdAndreas Huber    Res_value value;
2815778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
2825778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (value.dataType < Res_value::TYPE_FIRST_INT
2835778822d86b0337407514b9372562b86edfa91cdAndreas Huber                || value.dataType > Res_value::TYPE_LAST_INT) {
2845778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (outError != NULL) *outError = "attribute is not an integer value";
2855778822d86b0337407514b9372562b86edfa91cdAndreas Huber            return defValue;
2865778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2875778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
2885778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return value.data;
2895778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
2905778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2915778822d86b0337407514b9372562b86edfa91cdAndreas Huberstatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
2925778822d86b0337407514b9372562b86edfa91cdAndreas Huber        uint32_t attrRes, String8* outError)
2935778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
2945778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ssize_t idx = indexOfAttribute(tree, attrRes);
2955778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (idx < 0) {
2965778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return String8();
2975778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
2985778822d86b0337407514b9372562b86edfa91cdAndreas Huber    Res_value value;
2995778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
3005778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (value.dataType == Res_value::TYPE_STRING) {
3015778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t len;
3025778822d86b0337407514b9372562b86edfa91cdAndreas Huber            const uint16_t* str = tree.getAttributeStringValue(idx, &len);
3035778822d86b0337407514b9372562b86edfa91cdAndreas Huber            return str ? String8(str, len) : String8();
3045778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
3055778822d86b0337407514b9372562b86edfa91cdAndreas Huber        resTable->resolveReference(&value, 0);
3065778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (value.dataType != Res_value::TYPE_STRING) {
3075778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (outError != NULL) *outError = "attribute is not a string value";
3085778822d86b0337407514b9372562b86edfa91cdAndreas Huber            return String8();
3095778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
3105778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3115778822d86b0337407514b9372562b86edfa91cdAndreas Huber    size_t len;
3125778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const Res_value* value2 = &value;
3135778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
3147cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    return str ? String8(str, len) : String8();
3157cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden}
3167cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
3177cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden// These are attribute resource constants for the platform, as found
3187cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden// in android.R.attr
3197cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFaddenenum {
3207cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    NAME_ATTR = 0x01010003,
3215778822d86b0337407514b9372562b86edfa91cdAndreas Huber    VERSION_CODE_ATTR = 0x0101021b,
3225778822d86b0337407514b9372562b86edfa91cdAndreas Huber    VERSION_NAME_ATTR = 0x0101021c,
3235778822d86b0337407514b9372562b86edfa91cdAndreas Huber    LABEL_ATTR = 0x01010001,
3245778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ICON_ATTR = 0x01010002,
3255778822d86b0337407514b9372562b86edfa91cdAndreas Huber    MIN_SDK_VERSION_ATTR = 0x0101020c,
3265778822d86b0337407514b9372562b86edfa91cdAndreas Huber    MAX_SDK_VERSION_ATTR = 0x01010271,
3275778822d86b0337407514b9372562b86edfa91cdAndreas Huber    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
3285778822d86b0337407514b9372562b86edfa91cdAndreas Huber    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
3295778822d86b0337407514b9372562b86edfa91cdAndreas Huber    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
3305778822d86b0337407514b9372562b86edfa91cdAndreas Huber    REQ_NAVIGATION_ATTR = 0x0101022a,
3315778822d86b0337407514b9372562b86edfa91cdAndreas Huber    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
3325778822d86b0337407514b9372562b86edfa91cdAndreas Huber    TARGET_SDK_VERSION_ATTR = 0x01010270,
3335778822d86b0337407514b9372562b86edfa91cdAndreas Huber    TEST_ONLY_ATTR = 0x01010272,
3345778822d86b0337407514b9372562b86edfa91cdAndreas Huber    DENSITY_ATTR = 0x0101026c,
335717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    SMALL_SCREEN_ATTR = 0x01010284,
336717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    NORMAL_SCREEN_ATTR = 0x01010285,
337717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    LARGE_SCREEN_ATTR = 0x01010286,
338717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo};
339717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo
340717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjoconst char *getComponentName(String8 &pkgName, String8 &componentName) {
341717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    ssize_t idx = componentName.find(".");
342717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    String8 retStr(pkgName);
343717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    if (idx == 0) {
344717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo        retStr += componentName;
345717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    } else if (idx < 0) {
346717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo        retStr += ".";
347717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo        retStr += componentName;
348717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo    } else {
3495778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return componentName.string();
3505778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3515778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return retStr.string();
3525778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
3535778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3545778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
3555778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Handle the "dump" command, to extract select data from an archive.
3565778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
3575778822d86b0337407514b9372562b86edfa91cdAndreas Huberint doDump(Bundle* bundle)
3585778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
3595778822d86b0337407514b9372562b86edfa91cdAndreas Huber    status_t result = UNKNOWN_ERROR;
3605778822d86b0337407514b9372562b86edfa91cdAndreas Huber    Asset* asset = NULL;
3615778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3625778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getFileSpecCount() < 1) {
3635778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: no dump option specified\n");
3645778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return 1;
3655778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3665778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3675778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getFileSpecCount() < 2) {
3685778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: no dump file specified\n");
3695778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return 1;
3705778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3715778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3725778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char* option = bundle->getFileSpecEntry(0);
3735778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char* filename = bundle->getFileSpecEntry(1);
374496238cc7551d414067dcbbb4fe3bd801f205f95Andreas Huber
375496238cc7551d414067dcbbb4fe3bd801f205f95Andreas Huber    AssetManager assets;
376496238cc7551d414067dcbbb4fe3bd801f205f95Andreas Huber    void* assetsCookie;
377496238cc7551d414067dcbbb4fe3bd801f205f95Andreas Huber    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
378496238cc7551d414067dcbbb4fe3bd801f205f95Andreas Huber        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
379496238cc7551d414067dcbbb4fe3bd801f205f95Andreas Huber        return 1;
380575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber    }
381575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber
382575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber    const ResTable& res = assets.getResources(false);
383575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber    if (&res == NULL) {
384575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
385575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber        goto bail;
3865778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3875778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3885778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (strcmp("resources", option) == 0) {
3895778822d86b0337407514b9372562b86edfa91cdAndreas Huber        res.print(bundle->getValues());
3905778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3915778822d86b0337407514b9372562b86edfa91cdAndreas Huber    } else if (strcmp("xmltree", option) == 0) {
3925778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (bundle->getFileSpecCount() < 3) {
3935778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
3945778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
3955778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
3965778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3975778822d86b0337407514b9372562b86edfa91cdAndreas Huber        for (int i=2; i<bundle->getFileSpecCount(); i++) {
3985778822d86b0337407514b9372562b86edfa91cdAndreas Huber            const char* resname = bundle->getFileSpecEntry(i);
3995778822d86b0337407514b9372562b86edfa91cdAndreas Huber            ResXMLTree tree;
4005778822d86b0337407514b9372562b86edfa91cdAndreas Huber            asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
4015778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (asset == NULL) {
4025778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname);
4035778822d86b0337407514b9372562b86edfa91cdAndreas Huber                goto bail;
4045778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
4055778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4065778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (tree.setTo(asset->getBuffer(true),
4075778822d86b0337407514b9372562b86edfa91cdAndreas Huber                           asset->getLength()) != NO_ERROR) {
4085778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
4095778822d86b0337407514b9372562b86edfa91cdAndreas Huber                goto bail;
4105778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
4115778822d86b0337407514b9372562b86edfa91cdAndreas Huber            tree.restart();
4125778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printXMLBlock(&tree);
4135778822d86b0337407514b9372562b86edfa91cdAndreas Huber            delete asset;
4145778822d86b0337407514b9372562b86edfa91cdAndreas Huber            asset = NULL;
4155778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
4165778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4175778822d86b0337407514b9372562b86edfa91cdAndreas Huber    } else if (strcmp("xmlstrings", option) == 0) {
4185778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (bundle->getFileSpecCount() < 3) {
4195778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
4205778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
4215778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
4225778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4235778822d86b0337407514b9372562b86edfa91cdAndreas Huber        for (int i=2; i<bundle->getFileSpecCount(); i++) {
4245778822d86b0337407514b9372562b86edfa91cdAndreas Huber            const char* resname = bundle->getFileSpecEntry(i);
4255778822d86b0337407514b9372562b86edfa91cdAndreas Huber            ResXMLTree tree;
4265778822d86b0337407514b9372562b86edfa91cdAndreas Huber            asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
4275778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (asset == NULL) {
4285778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname);
4295778822d86b0337407514b9372562b86edfa91cdAndreas Huber                goto bail;
4305778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
4315778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4325778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (tree.setTo(asset->getBuffer(true),
4335778822d86b0337407514b9372562b86edfa91cdAndreas Huber                           asset->getLength()) != NO_ERROR) {
4345778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
4355778822d86b0337407514b9372562b86edfa91cdAndreas Huber                goto bail;
4365778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
4375778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printStringPool(&tree.getStrings());
4385778822d86b0337407514b9372562b86edfa91cdAndreas Huber            delete asset;
4395778822d86b0337407514b9372562b86edfa91cdAndreas Huber            asset = NULL;
4405778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
4415778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4425778822d86b0337407514b9372562b86edfa91cdAndreas Huber    } else {
4435778822d86b0337407514b9372562b86edfa91cdAndreas Huber        ResXMLTree tree;
4445778822d86b0337407514b9372562b86edfa91cdAndreas Huber        asset = assets.openNonAsset("AndroidManifest.xml",
4455778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                            Asset::ACCESS_BUFFER);
4465778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (asset == NULL) {
4475778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
4485778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
4495778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
4505778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4515778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (tree.setTo(asset->getBuffer(true),
4525778822d86b0337407514b9372562b86edfa91cdAndreas Huber                       asset->getLength()) != NO_ERROR) {
4535778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
4545778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
4555778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
4565778822d86b0337407514b9372562b86edfa91cdAndreas Huber        tree.restart();
4575778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4585778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (strcmp("permissions", option) == 0) {
4595778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t len;
4605778822d86b0337407514b9372562b86edfa91cdAndreas Huber            ResXMLTree::event_code_t code;
4615778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int depth = 0;
4625778822d86b0337407514b9372562b86edfa91cdAndreas Huber            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
4635778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (code == ResXMLTree::END_TAG) {
4645778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    depth--;
4655778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    continue;
4665778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
4675778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (code != ResXMLTree::START_TAG) {
4685778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    continue;
4695778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
4705778822d86b0337407514b9372562b86edfa91cdAndreas Huber                depth++;
4715778822d86b0337407514b9372562b86edfa91cdAndreas Huber                String8 tag(tree.getElementName(&len));
4725778822d86b0337407514b9372562b86edfa91cdAndreas Huber                //printf("Depth %d tag %s\n", depth, tag.string());
4735778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (depth == 1) {
4745778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (tag != "manifest") {
4755778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
4765778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        goto bail;
4775778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
4785778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
4795778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    printf("package: %s\n", pkg.string());
4805778822d86b0337407514b9372562b86edfa91cdAndreas Huber                } else if (depth == 2 && tag == "permission") {
4815778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    String8 error;
4825778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    String8 name = getAttribute(tree, NAME_ATTR, &error);
4835778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (error != "") {
4845778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        fprintf(stderr, "ERROR: %s\n", error.string());
4855778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        goto bail;
4865778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
4875778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    printf("permission: %s\n", name.string());
4885778822d86b0337407514b9372562b86edfa91cdAndreas Huber                } else if (depth == 2 && tag == "uses-permission") {
4895778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    String8 error;
4905778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    String8 name = getAttribute(tree, NAME_ATTR, &error);
4915778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (error != "") {
4925778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        fprintf(stderr, "ERROR: %s\n", error.string());
4935778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        goto bail;
4945778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
4955778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    printf("uses-permission: %s\n", name.string());
4965778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
4975778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
4985778822d86b0337407514b9372562b86edfa91cdAndreas Huber        } else if (strcmp("badging", option) == 0) {
4995778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t len;
5005778822d86b0337407514b9372562b86edfa91cdAndreas Huber            ResXMLTree::event_code_t code;
5015778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int depth = 0;
5025778822d86b0337407514b9372562b86edfa91cdAndreas Huber            String8 error;
5035778822d86b0337407514b9372562b86edfa91cdAndreas Huber            bool withinActivity = false;
5045778822d86b0337407514b9372562b86edfa91cdAndreas Huber            bool isMainActivity = false;
5055778822d86b0337407514b9372562b86edfa91cdAndreas Huber            bool isLauncherActivity = false;
5065778822d86b0337407514b9372562b86edfa91cdAndreas Huber            bool withinApplication = false;
5075778822d86b0337407514b9372562b86edfa91cdAndreas Huber            bool withinReceiver = false;
5085778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int targetSdk = 0;
5095778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int smallScreen = 1;
5105778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int normalScreen = 1;
5115778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int largeScreen = 1;
5125778822d86b0337407514b9372562b86edfa91cdAndreas Huber            String8 pkg;
5135778822d86b0337407514b9372562b86edfa91cdAndreas Huber            String8 activityName;
5145778822d86b0337407514b9372562b86edfa91cdAndreas Huber            String8 activityLabel;
5155778822d86b0337407514b9372562b86edfa91cdAndreas Huber            String8 activityIcon;
5165778822d86b0337407514b9372562b86edfa91cdAndreas Huber            String8 receiverName;
5175778822d86b0337407514b9372562b86edfa91cdAndreas Huber            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
5185778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (code == ResXMLTree::END_TAG) {
5195778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    depth--;
5205778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    continue;
5215778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
5225778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (code != ResXMLTree::START_TAG) {
5235778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    continue;
5245778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
5255778822d86b0337407514b9372562b86edfa91cdAndreas Huber                depth++;
5265778822d86b0337407514b9372562b86edfa91cdAndreas Huber                String8 tag(tree.getElementName(&len));
5275778822d86b0337407514b9372562b86edfa91cdAndreas Huber                //printf("Depth %d tag %s\n", depth, tag.string());
5285778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (depth == 1) {
5295778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (tag != "manifest") {
5305778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
531c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                        goto bail;
5325778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
5335778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    pkg = getAttribute(tree, NULL, "package", NULL);
5345778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    printf("package: name='%s' ", pkg.string());
5355778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
5365778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (error != "") {
5375778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
5385778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        goto bail;
5395778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
5405778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (versionCode > 0) {
5415778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf("versionCode='%d' ", versionCode);
5425778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    } else {
5435778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf("versionCode='' ");
5445778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
5455778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    String8 versionName = getAttribute(tree, VERSION_NAME_ATTR, &error);
5465778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (error != "") {
5475778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
5485778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        goto bail;
5495778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
5505778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    printf("versionName='%s'\n", versionName.string());
551575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber                } else if (depth == 2) {
5525778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    withinApplication = false;
5535778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (tag == "application") {
5545778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        withinApplication = true;
5555778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        String8 label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
5565778822d86b0337407514b9372562b86edfa91cdAndreas Huber                         if (error != "") {
5575778822d86b0337407514b9372562b86edfa91cdAndreas Huber                             fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string());
5585778822d86b0337407514b9372562b86edfa91cdAndreas Huber                             goto bail;
5595778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
5605778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf("application: label='%s' ", label.string());
5615778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
562575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber                        if (error != "") {
5635778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
5645778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
5655778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
5665778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf("icon='%s'\n", icon.string());
5675778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
5685778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
5695778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
5705778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
5715778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
5725778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (testOnly != 0) {
5735778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            printf("testOnly='%d'\n", testOnly);
5745778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
5755778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    } else if (tag == "uses-sdk") {
5765778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
5775778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
5785778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            error = "";
5795778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
5805778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (error != "") {
581717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
5825778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                        error.string());
583717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo                                goto bail;
5845778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
5855778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (name == "Donut") targetSdk = 4;
5865778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            printf("sdkVersion:'%s'\n", name.string());
5875778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        } else if (code != -1) {
5885778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            targetSdk = code;
589717fd3d4328abf524978ce9c125ab8ae8d6bffadMartin Storsjo                            printf("sdkVersion:'%d'\n", code);
5901bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                        }
5911bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
5921bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                        if (code != -1) {
5931bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                            printf("maxSdkVersion:'%d'\n", code);
5941bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                        }
5955778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
5965778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
5975778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            error = "";
5985778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
5995778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (error != "") {
6005778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
6015778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                        error.string());
6025778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                goto bail;
6035778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
6046507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
6056507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden                            printf("targetSdkVersion:'%s'\n", name.string());
6066507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden                        } else if (code != -1) {
6075778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (targetSdk < code) {
6085778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                targetSdk = code;
6095778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
6105778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            printf("targetSdkVersion:'%d'\n", code);
6117cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        }
6127cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                    } else if (tag == "uses-configuration") {
6137cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        int32_t reqTouchScreen = getIntegerAttribute(tree,
6147cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
6157cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        int32_t reqKeyboardType = getIntegerAttribute(tree,
6167cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
6177cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
6187cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
6197cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        int32_t reqNavigation = getIntegerAttribute(tree,
6207cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                                REQ_NAVIGATION_ATTR, NULL, 0);
6216507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
6227cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
6237cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        printf("uses-configuation:");
6247cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        if (reqTouchScreen != 0) {
6257cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                            printf(" reqTouchScreen='%d'", reqTouchScreen);
6267cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        }
6277cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        if (reqKeyboardType != 0) {
6287cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                            printf(" reqKeyboardType='%d'", reqKeyboardType);
6297cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        }
6307cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        if (reqHardKeyboard != 0) {
6317cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
6327cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        }
6337cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        if (reqNavigation != 0) {
6347cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                            printf(" reqNavigation='%d'", reqNavigation);
6357cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        }
6367cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        if (reqFiveWayNav != 0) {
6377cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
6387cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        }
6397cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        printf("\n");
6407cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                    } else if (tag == "supports-density") {
6417cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                        int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error);
6425778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
6435778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n",
6445778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                    error.string());
6455778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
6465778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
6475778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf("supports-density:'%d'\n", dens);
6485778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    } else if (tag == "supports-screens") {
6495778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        smallScreen = getIntegerAttribute(tree,
6505778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                SMALL_SCREEN_ATTR, NULL, 1);
6515778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        normalScreen = getIntegerAttribute(tree,
6525778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                NORMAL_SCREEN_ATTR, NULL, 1);
6535778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        largeScreen = getIntegerAttribute(tree,
6545778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                LARGE_SCREEN_ATTR, NULL, 1);
6555778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
6565778822d86b0337407514b9372562b86edfa91cdAndreas Huber                } else if (depth == 3 && withinApplication) {
657eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                    withinActivity = false;
658eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                    withinReceiver = false;
659eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                    if(tag == "activity") {
660eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                        withinActivity = true;
661eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                        activityName = getAttribute(tree, NAME_ATTR, &error);
6625778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
663eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
6645778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
665eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                        }
6665778822d86b0337407514b9372562b86edfa91cdAndreas Huber
667eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                        activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
6685778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
669eb61431af13741aa8b7e57a39f69bba5a6c190dcAndreas Huber                            fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n", error.string());
6705778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
6711bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                        }
672ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber
673ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber                        activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
674ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber                        if (error != "") {
675ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
6765778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
6775778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
6785778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    } else if (tag == "uses-library") {
6795778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
6805778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
6815778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string());
6825778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
6835778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
6845778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf("uses-library:'%s'\n", libraryName.string());
6855778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    } else if (tag == "receiver") {
6865778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        withinReceiver = true;
6875778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        receiverName = getAttribute(tree, NAME_ATTR, &error);
688575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber
6895778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (error != "") {
6905778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
6915778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            goto bail;
6925778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
6935778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
6945778822d86b0337407514b9372562b86edfa91cdAndreas Huber                } else if (depth == 5) {
6955778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    if (withinActivity) {
6965778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (tag == "action") {
6975778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            //printf("LOG: action tag\n");
6985778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            String8 action = getAttribute(tree, NAME_ATTR, &error);
6995778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (error != "") {
7005778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
7015778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                goto bail;
7025778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
7035778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (action == "android.intent.action.MAIN") {
7045778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                isMainActivity = true;
7055778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                //printf("LOG: isMainActivity==true\n");
7065778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
7075778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        } else if (tag == "category") {
7085778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            String8 category = getAttribute(tree, NAME_ATTR, &error);
7095778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (error != "") {
7105778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
7115778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                goto bail;
7125778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
7135778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (category == "android.intent.category.LAUNCHER") {
7145778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                isLauncherActivity = true;
7155778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                //printf("LOG: isLauncherActivity==true\n");
7165778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
7175778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
7185778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    } else if (withinReceiver) {
7195778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        if (tag == "action") {
7205778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            String8 action = getAttribute(tree, NAME_ATTR, &error);
7215778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (error != "") {
7225778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
7235778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                goto bail;
7245778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
7255778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
7265778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                const char *rName = getComponentName(pkg, receiverName);
727575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber                                if (rName != NULL) {
7285778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                    printf("gadget-receiver:'%s/%s'\n", pkg.string(), rName);
7295778822d86b0337407514b9372562b86edfa91cdAndreas Huber                                }
7305778822d86b0337407514b9372562b86edfa91cdAndreas Huber                            }
7315778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        }
7325778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
7335778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
7345778822d86b0337407514b9372562b86edfa91cdAndreas Huber
735c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                if (depth < 2) {
736c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                    withinApplication = false;
737c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                }
7385778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (depth < 3) {
7395778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    //if (withinActivity) printf("LOG: withinActivity==false\n");
7405778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    withinActivity = false;
7415778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    withinReceiver = false;
7428ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                }
7438ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber
7448ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                if (depth < 5) {
7458ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    //if (isMainActivity) printf("LOG: isMainActivity==false\n");
7468ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n");
7478ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    isMainActivity = false;
7488ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    isLauncherActivity = false;
7498ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                }
7508ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber
7518ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                if (withinActivity && isMainActivity && isLauncherActivity) {
7528ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    printf("launchable activity:");
7538ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    const char *aName = getComponentName(pkg, activityName);
7548ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    if (aName != NULL) {
7558ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                        printf(" name='%s'", aName);
7568ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    }
7578ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                    printf("label='%s' icon='%s'\n",
7588ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber                           activityLabel.string(),
759575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber                           activityIcon.string());
760575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber                }
7618ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber            }
7628ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber
7638ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber            // Determine default values for any unspecified screen sizes,
7648ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber            // based on the target SDK of the package.  As of 4 (donut)
7658ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber            // the screen size support was introduced, so all default to
7665778822d86b0337407514b9372562b86edfa91cdAndreas Huber            // enabled.
7675778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (smallScreen > 0) {
7685778822d86b0337407514b9372562b86edfa91cdAndreas Huber                smallScreen = targetSdk >= 4 ? -1 : 0;
7695778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
7705778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (normalScreen > 0) {
7715778822d86b0337407514b9372562b86edfa91cdAndreas Huber                normalScreen = -1;
772575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber            }
773575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber            if (largeScreen > 0) {
7745778822d86b0337407514b9372562b86edfa91cdAndreas Huber                largeScreen = targetSdk >= 4 ? -1 : 0;
7755778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
7765778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf("supports-screens:");
7775778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (smallScreen != 0) printf(" 'small'");
7785778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (normalScreen != 0) printf(" 'normal'");
7795778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (largeScreen != 0) printf(" 'large'");
7805778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf("\n");
7815778822d86b0337407514b9372562b86edfa91cdAndreas Huber
782c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            printf("locales:");
783c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            Vector<String8> locales;
784c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            res.getLocales(&locales);
7855778822d86b0337407514b9372562b86edfa91cdAndreas Huber            const size_t NL = locales.size();
7865778822d86b0337407514b9372562b86edfa91cdAndreas Huber            for (size_t i=0; i<NL; i++) {
7875778822d86b0337407514b9372562b86edfa91cdAndreas Huber                const char* localeStr =  locales[i].string();
7885778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (localeStr == NULL || strlen(localeStr) == 0) {
7892d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber                    localeStr = "--_--";
7902d8bedd05437b6fccdbc6bf70f673ffd86744d59Andreas Huber                }
7915778822d86b0337407514b9372562b86edfa91cdAndreas Huber                printf(" '%s'", localeStr);
7925778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
7935778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf("\n");
7945778822d86b0337407514b9372562b86edfa91cdAndreas Huber
7955778822d86b0337407514b9372562b86edfa91cdAndreas Huber            Vector<ResTable_config> configs;
7965778822d86b0337407514b9372562b86edfa91cdAndreas Huber            res.getConfigurations(&configs);
7975778822d86b0337407514b9372562b86edfa91cdAndreas Huber            SortedVector<int> densities;
7985778822d86b0337407514b9372562b86edfa91cdAndreas Huber            const size_t NC = configs.size();
7995778822d86b0337407514b9372562b86edfa91cdAndreas Huber            for (size_t i=0; i<NC; i++) {
8005778822d86b0337407514b9372562b86edfa91cdAndreas Huber                int dens = configs[i].density;
8015778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (dens == 0) dens = 160;
8025778822d86b0337407514b9372562b86edfa91cdAndreas Huber                densities.add(dens);
803575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber            }
804575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber
8055778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf("densities:");
806575a5361fc970476cd7979638ee3ac00cc6e5024Andreas Huber            const size_t ND = densities.size();
8075778822d86b0337407514b9372562b86edfa91cdAndreas Huber            for (size_t i=0; i<ND; i++) {
8085778822d86b0337407514b9372562b86edfa91cdAndreas Huber                printf(" '%d'", densities[i]);
8095778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
8105778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf("\n");
8115778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8125778822d86b0337407514b9372562b86edfa91cdAndreas Huber            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
8135778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (dir != NULL) {
8145778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (dir->getFileCount() > 0) {
8155778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    printf("native-code:");
8165778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    for (size_t i=0; i<dir->getFileCount(); i++) {
8175778822d86b0337407514b9372562b86edfa91cdAndreas Huber                        printf(" '%s'", dir->getFileName(i).string());
8185778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    }
819c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                    printf("\n");
820c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                }
821c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber                delete dir;
822c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            }
823c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        } else if (strcmp("configurations", option) == 0) {
824c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            Vector<ResTable_config> configs;
8255778822d86b0337407514b9372562b86edfa91cdAndreas Huber            res.getConfigurations(&configs);
8265778822d86b0337407514b9372562b86edfa91cdAndreas Huber            const size_t N = configs.size();
8275778822d86b0337407514b9372562b86edfa91cdAndreas Huber            for (size_t i=0; i<N; i++) {
8285778822d86b0337407514b9372562b86edfa91cdAndreas Huber                printf("%s\n", configs[i].toString().string());
8295778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
8305778822d86b0337407514b9372562b86edfa91cdAndreas Huber        } else {
8315778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
8325778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
8335778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
8345778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
8355778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8365778822d86b0337407514b9372562b86edfa91cdAndreas Huber    result = NO_ERROR;
8375778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8385778822d86b0337407514b9372562b86edfa91cdAndreas Huberbail:
8395778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (asset) {
8405778822d86b0337407514b9372562b86edfa91cdAndreas Huber        delete asset;
8415778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
8425778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return (result != NO_ERROR);
8435778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
8445778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8455778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8465778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
8475778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Handle the "add" command, which wants to add files to a new or
8485778822d86b0337407514b9372562b86edfa91cdAndreas Huber * pre-existing archive.
8495778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
8505778822d86b0337407514b9372562b86edfa91cdAndreas Huberint doAdd(Bundle* bundle)
8515778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
8525778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ZipFile* zip = NULL;
8535778822d86b0337407514b9372562b86edfa91cdAndreas Huber    status_t result = UNKNOWN_ERROR;
8545778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char* zipFileName;
8555778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8565778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getUpdate()) {
8575778822d86b0337407514b9372562b86edfa91cdAndreas Huber        /* avoid confusion */
8585778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: can't use '-u' with add\n");
8595778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
8605778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
8615778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8625778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (bundle->getFileSpecCount() < 1) {
8635778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: must specify zip file name\n");
8645778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
8655778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
8665778822d86b0337407514b9372562b86edfa91cdAndreas Huber    zipFileName = bundle->getFileSpecEntry(0);
8675778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8680db280176bd3277e3256252d063f3712b1905ba9Andreas Huber    if (bundle->getFileSpecCount() < 2) {
8690db280176bd3277e3256252d063f3712b1905ba9Andreas Huber        fprintf(stderr, "NOTE: nothing to do\n");
8705778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
8715778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
8725778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8735778822d86b0337407514b9372562b86edfa91cdAndreas Huber    zip = openReadWrite(zipFileName, true);
8745778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (zip == NULL) {
8755778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
8765778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
8775778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
8785778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8795778822d86b0337407514b9372562b86edfa91cdAndreas Huber    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
8805778822d86b0337407514b9372562b86edfa91cdAndreas Huber        const char* fileName = bundle->getFileSpecEntry(i);
8815778822d86b0337407514b9372562b86edfa91cdAndreas Huber
8825778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
8835778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf(" '%s'... (from gzip)\n", fileName);
8845778822d86b0337407514b9372562b86edfa91cdAndreas Huber            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
8855778822d86b0337407514b9372562b86edfa91cdAndreas Huber        } else {
8865778822d86b0337407514b9372562b86edfa91cdAndreas Huber            printf(" '%s'...\n", fileName);
8875778822d86b0337407514b9372562b86edfa91cdAndreas Huber            result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
8885778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
8895778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (result != NO_ERROR) {
8905778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
8915778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (result == NAME_NOT_FOUND)
8925778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, ": file not found\n");
8935778822d86b0337407514b9372562b86edfa91cdAndreas Huber            else if (result == ALREADY_EXISTS)
8945778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, ": already exists in archive\n");
8955778822d86b0337407514b9372562b86edfa91cdAndreas Huber            else
8965778822d86b0337407514b9372562b86edfa91cdAndreas Huber                fprintf(stderr, "\n");
8975778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
8985778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
8995778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
9005778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9015778822d86b0337407514b9372562b86edfa91cdAndreas Huber    result = NO_ERROR;
9025778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9035778822d86b0337407514b9372562b86edfa91cdAndreas Huberbail:
9045778822d86b0337407514b9372562b86edfa91cdAndreas Huber    delete zip;
9055778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return (result != NO_ERROR);
9065778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
9075778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9085778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9091bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber/*
9107541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber * Delete files from an existing archive.
9117541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber */
9127541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huberint doRemove(Bundle* bundle)
9137541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber{
9147541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber    ZipFile* zip = NULL;
9157541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber    status_t result = UNKNOWN_ERROR;
9167541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber    const char* zipFileName;
9177541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber
9187541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber    if (bundle->getFileSpecCount() < 1) {
9197541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber        fprintf(stderr, "ERROR: must specify zip file name\n");
9201bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber        goto bail;
9211bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    }
9227541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber    zipFileName = bundle->getFileSpecEntry(0);
9231bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber
9241bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    if (bundle->getFileSpecCount() < 2) {
9257541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber        fprintf(stderr, "NOTE: nothing to do\n");
9267541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber        goto bail;
9277541ff5d83a3e77cb533841a0326a241550b95d9Andreas Huber    }
9281bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber
9291bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    zip = openReadWrite(zipFileName, false);
9301bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    if (zip == NULL) {
9315778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
9325778822d86b0337407514b9372562b86edfa91cdAndreas Huber            zipFileName);
9331bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber        goto bail;
9341bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber    }
9355778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9365778822d86b0337407514b9372562b86edfa91cdAndreas Huber    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
9375778822d86b0337407514b9372562b86edfa91cdAndreas Huber        const char* fileName = bundle->getFileSpecEntry(i);
9385778822d86b0337407514b9372562b86edfa91cdAndreas Huber        ZipEntry* entry;
9395778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9405778822d86b0337407514b9372562b86edfa91cdAndreas Huber        entry = zip->getEntryByName(fileName);
9415778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (entry == NULL) {
9428ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber            printf(" '%s' NOT FOUND\n", fileName);
9438ee516a515c70a492c395b67ce12e19e7d159804Andreas Huber            continue;
9445778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
9455778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9465778822d86b0337407514b9372562b86edfa91cdAndreas Huber        result = zip->remove(entry);
9475778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9487cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden        if (result != NO_ERROR) {
9497cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
9507cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden                bundle->getFileSpecEntry(i), zipFileName);
9517cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden            goto bail;
9527cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden        }
9537cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    }
9547cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
9557cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    /* update the archive */
9567cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    zip->flush();
9577cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
9587cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFaddenbail:
9597cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    delete zip;
9607cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden    return (result != NO_ERROR);
9617cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden}
9627cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
9637cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden
9647cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden/*
9657cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden * Package up an asset directory and associated application files.
9667cd58537932ef6f481f68be0b9c597a89cebdfecAndy McFadden */
9675778822d86b0337407514b9372562b86edfa91cdAndreas Huberint doPackage(Bundle* bundle)
9685778822d86b0337407514b9372562b86edfa91cdAndreas Huber{
9695778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char* outputAPKFile;
9705778822d86b0337407514b9372562b86edfa91cdAndreas Huber    int retVal = 1;
9715778822d86b0337407514b9372562b86edfa91cdAndreas Huber    status_t err;
9725778822d86b0337407514b9372562b86edfa91cdAndreas Huber    sp<AaptAssets> assets;
9735778822d86b0337407514b9372562b86edfa91cdAndreas Huber    int N;
9745778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9755778822d86b0337407514b9372562b86edfa91cdAndreas Huber    // -c zz_ZZ means do pseudolocalization
9765778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ResourceFilter filter;
9775778822d86b0337407514b9372562b86edfa91cdAndreas Huber    err = filter.parse(bundle->getConfigurations());
9785778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (err != NO_ERROR) {
9795778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
9805778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
9815778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (filter.containsPseudo()) {
9825778822d86b0337407514b9372562b86edfa91cdAndreas Huber        bundle->setPseudolocalize(true);
9835778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
9845778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9855778822d86b0337407514b9372562b86edfa91cdAndreas Huber    N = bundle->getFileSpecCount();
9865778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
9875778822d86b0337407514b9372562b86edfa91cdAndreas Huber            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
9885778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "ERROR: no input files\n");
9895778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
9905778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
9915778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9925778822d86b0337407514b9372562b86edfa91cdAndreas Huber    outputAPKFile = bundle->getOutputAPKFile();
9935778822d86b0337407514b9372562b86edfa91cdAndreas Huber
9945778822d86b0337407514b9372562b86edfa91cdAndreas Huber    // Make sure the filenames provided exist and are of the appropriate type.
9955778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (outputAPKFile) {
9965778822d86b0337407514b9372562b86edfa91cdAndreas Huber        FileType type;
9975778822d86b0337407514b9372562b86edfa91cdAndreas Huber        type = getFileType(outputAPKFile);
9985778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
9995778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr,
10005778822d86b0337407514b9372562b86edfa91cdAndreas Huber                "ERROR: output file '%s' exists but is not regular file\n",
10015778822d86b0337407514b9372562b86edfa91cdAndreas Huber                outputAPKFile);
10025778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
10035778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
1004c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    }
1005c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber
1006c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    // Load the assets.
1007c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    assets = new AaptAssets();
1008c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    err = assets->slurpFromArgs(bundle);
1009c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    if (err < 0) {
1010c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        goto bail;
1011c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    }
1012c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber
1013c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    if (bundle->getVerbose()) {
1014c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        assets->print();
1015c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    }
1016c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber
1017c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    // If they asked for any files that need to be compiled, do so.
1018c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
1019c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        err = buildResources(bundle, assets);
1020c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        if (err != 0) {
1021c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber            goto bail;
1022c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        }
1023c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    }
1024c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber
1025c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber    // At this point we've read everything and processed everything.  From here
10265778822d86b0337407514b9372562b86edfa91cdAndreas Huber    // on out it's just writing output files.
10275778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (SourcePos::hasErrors()) {
10285778822d86b0337407514b9372562b86edfa91cdAndreas Huber        goto bail;
10295778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
10305778822d86b0337407514b9372562b86edfa91cdAndreas Huber
10315778822d86b0337407514b9372562b86edfa91cdAndreas Huber    // Write out R.java constants
10325778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (assets->getPackage() == assets->getSymbolsPrivatePackage()) {
10335778822d86b0337407514b9372562b86edfa91cdAndreas Huber        err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
10345778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (err < 0) {
10355778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
10366507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden        }
10376507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden    } else {
10386507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
10396507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden        if (err < 0) {
10406507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden            goto bail;
10416507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden        }
10426507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
10436507d14c6d10f93d390de62b9eed267f9b544985Andy McFadden        if (err < 0) {
10445778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
10455778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
10465778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
10475778822d86b0337407514b9372562b86edfa91cdAndreas Huber
10485778822d86b0337407514b9372562b86edfa91cdAndreas Huber    // Write the apk
10495778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (outputAPKFile) {
10505778822d86b0337407514b9372562b86edfa91cdAndreas Huber        err = writeAPK(bundle, assets, String8(outputAPKFile));
10515778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (err != NO_ERROR) {
10525778822d86b0337407514b9372562b86edfa91cdAndreas Huber            fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile);
10535778822d86b0337407514b9372562b86edfa91cdAndreas Huber            goto bail;
10545778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
10555778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
10565778822d86b0337407514b9372562b86edfa91cdAndreas Huber
10575778822d86b0337407514b9372562b86edfa91cdAndreas Huber    retVal = 0;
10585778822d86b0337407514b9372562b86edfa91cdAndreas Huberbail:
10595778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (SourcePos::hasErrors()) {
10605778822d86b0337407514b9372562b86edfa91cdAndreas Huber        SourcePos::printErrors(stderr);
10615778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
10625778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return retVal;
10635778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
10645778822d86b0337407514b9372562b86edfa91cdAndreas Huber