Command.cpp revision caf797c84a6a2829662872e0df93fcd61da78d51
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Android Asset Packaging Tool main entry point.
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
6fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski#include "ApkBuilder.h"
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Bundle.h"
82c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include "Images.h"
92c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include "Main.h"
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h"
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "XMLNode.h"
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/Errors.h>
152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/KeyedVector.h>
162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/List.h>
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h>
182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/SortedVector.h>
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/threads.h>
202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <utils/Vector.h>
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h>
232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski#include <fcntl.h>
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
27ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski#ifndef AAPT_VERSION
28ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski    #define AAPT_VERSION ""
29ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski#endif
30ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Show version info.  All the cool kids do it.
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doVersion(Bundle* bundle)
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 0) {
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("(ignoring extra arguments)\n");
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
39ad751224401564dcc8338df3d5c4c5de7722be8fAdam Lesinski    printf("Android Asset Packaging Tool, v0.2-" AAPT_VERSION "\n");
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read only.  The call fails if the file doesn't exist.
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadOnly(const char* fileName)
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip;
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, ZipFile::kOpenReadOnly);
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result == NAME_NOT_FOUND) {
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (result == PERMISSION_DENIED) {
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fileName);
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read-write.  The file will be created if it doesn't
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * already exist and "okayToCreate" is set.
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadWrite(const char* fileName, bool okayToCreate)
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int flags;
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    flags = ZipFile::kOpenReadWrite;
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (okayToCreate) {
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= ZipFile::kOpenCreate;
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, flags);
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zip = NULL;
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return a short string describing the compression method.
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char* compressionName(int method)
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (method == ZipEntry::kCompressStored) {
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Stored";
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (method == ZipEntry::kCompressDeflated) {
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Deflated";
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Unknown";
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the percent reduction in size (0% == no compression).
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint calcPercent(long uncompressedLen, long compressedLen)
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!uncompressedLen) {
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "list" command, which can be a simple file dump or
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a verbose listing.
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The verbose listing closely matches the output of the Info-ZIP "unzip"
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * command.
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doList(Bundle* bundle)
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ZipEntry* entry;
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long totalUncLen, totalCompLen;
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 1) {
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: specify zip file name (only)\n");
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadOnly(zipFileName);
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count, i;
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Archive:  %s\n", zipFileName);
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    totalUncLen = totalCompLen = 0;
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = zip->getNumEntries();
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByIndex(i);
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getVerbose()) {
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char dateBuf[32];
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            time_t when;
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            when = entry->getModWhen();
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localtime(&when));
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getUncompressedLen(),
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionName(entry->getCompressionMethod()),
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getCompressedLen(),
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                calcPercent(entry->getUncompressedLen(),
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            entry->getCompressedLen()),
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t) entry->getLFHOffset(),
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                dateBuf,
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getCRC32(),
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getFileName());
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s\n", entry->getFileName());
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalUncLen += entry->getUncompressedLen();
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalCompLen += entry->getCompressedLen();
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "--------          -------  ---                            -------\n");
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("%8ld          %7ld  %2d%%                            %d files\n",
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalUncLen,
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalCompLen,
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            calcPercent(totalUncLen, totalCompLen),
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zip->getNumEntries());
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getAndroidList()) {
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AssetManager assets;
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResTable& res = assets.getResources(false);
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (&res == NULL) {
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo resource table found.\n");
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nResource table:\n");
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.print(false);
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = tree.getAttributeCount();
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.getAttributeNameResID(i) == attrRes) {
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return (ssize_t)i;
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return -1;
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 getAttribute(const ResXMLTree& tree, const char* ns,
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* attr, String8* outError)
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8* outError, int32_t defValue = -1)
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError, int32_t defValue = -1)
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_REFERENCE) {
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(&value, 0);
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError)
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_STRING) {
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const uint16_t* str = tree.getAttributeStringValue(idx, &len);
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return str ? String8(str, len) : String8();
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        resTable->resolveReference(&value, 0);
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Res_value* value2 = &value;
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable,
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResXMLTree& tree, uint32_t attrRes, String8* outError)
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outError != NULL) {
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outError = "attribute could not be found";
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, value) != NO_ERROR) {
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value->dataType == Res_value::TYPE_REFERENCE) {
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(value, 0);
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // The attribute was found and was resolved if need be.
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outError != NULL) {
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outError = "error getting resolved resource attribute";
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38976327314d2238e105f8b94909f9c0cf85caca318Maurice Chustatic void printResolvedResourceAttribute(const ResTable* resTable, const ResXMLTree& tree,
39076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        uint32_t attrRes, String8 attrLabel, String8* outError)
39176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu{
39276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    Res_value value;
39376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    getResolvedResourceAttribute(&value, resTable, tree, attrRes, outError);
39476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (*outError != "") {
39576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        *outError = "error print resolved resource attribute";
39676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        return;
39776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
39876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    if (value.dataType == Res_value::TYPE_STRING) {
39976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        String8 result = getResolvedAttribute(resTable, tree, attrRes, outError);
4002675f769673f69b0661ddee346292f25cb30a296Maurice Chu        printf("%s='%s'", attrLabel.string(),
4012675f769673f69b0661ddee346292f25cb30a296Maurice Chu                ResTable::normalizeForOutput(result.string()).string());
40276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
40376327314d2238e105f8b94909f9c0cf85caca318Maurice Chu            value.dataType <= Res_value::TYPE_LAST_INT) {
40476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='%d'", attrLabel.string(), value.data);
40576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    } else {
40676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
40776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu    }
40876327314d2238e105f8b94909f9c0cf85caca318Maurice Chu}
40976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
416a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
4179d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    EXPORTED_ATTR = 0x01010010,
4189d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    GRANT_URI_PERMISSIONS_ATTR = 0x0101001b,
41994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    RESOURCE_ATTR = 0x01010025,
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
441caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski    INSTALL_LOCATION_ATTR = 0x010102b7,
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
44894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    CATEGORY_ATTR = 0x010103e8,
4490a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn    BANNER_ATTR = 0x10103f2,
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4522675f769673f69b0661ddee346292f25cb30a296Maurice ChuString8 getComponentName(String8 &pkgName, String8 &componentName) {
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
4612675f769673f69b0661ddee346292f25cb30a296Maurice Chu        return componentName;
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4632675f769673f69b0661ddee346292f25cb30a296Maurice Chu    return retStr;
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4669cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
4849cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        const char16_t* ctag16 = tree.getElementName(&len);
4859cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        if (ctag16 == NULL) {
4869cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            *outError = "failed to get XML element name (bad string pool)";
4879cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            return;
4889cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        }
4899cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski        String8 tag(ctag16);
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenSize = getIntegerAttribute(tree,
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_SIZE_ATTR, NULL, -1);
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenDensity = getIntegerAttribute(tree,
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_DENSITY_ATTR, NULL, -1);
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
50758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1) {
50858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
50958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (maxSdkVersion != -1) {
51058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski         printf(" maxSdkVersion='%d'", maxSdkVersion);
51158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
51258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("\n");
51358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
51458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    if (optional) {
51558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("optional-permission: name='%s'",
51658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                ResTable::normalizeForOutput(name.string()).string());
51758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        if (maxSdkVersion != -1) {
51858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            printf(" maxSdkVersion='%d'", maxSdkVersion);
51958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        }
52058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski        printf("\n");
52158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    }
52258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
52358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
52458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinskistatic void printUsesImpliedPermission(const String8& name, const String8& reason) {
52558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski    printf("uses-implied-permission: name='%s' reason='%s'\n",
52658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(name.string()).string(),
52758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski            ResTable::normalizeForOutput(reason.string()).string());
52858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski}
52958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
53094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam LesinskiVector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
53194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        String8 *outError = NULL)
53294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski{
53394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
53494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    if (aidAsset == NULL) {
53594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (outError != NULL) *outError = "xml resource does not exist";
53694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        return Vector<String8>();
53794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
53894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
53994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
54094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    bool withinApduService = false;
54294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    Vector<String8> categories;
54394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    String8 error;
54594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree tree;
54694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
54794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
54894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    size_t len;
54994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    int depth = 0;
55094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    ResXMLTree::event_code_t code;
55194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
55294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        if (code == ResXMLTree::END_TAG) {
55394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth--;
5549cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
5559cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
5569cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
5579cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
5589cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
5599cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
56094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 0 && tag == serviceTagName) {
56294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                withinApduService = false;
56394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
56494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
56594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        } else if (code == ResXMLTree::START_TAG) {
56694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            depth++;
5679cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            const char16_t* ctag16 = tree.getElementName(&len);
5689cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            if (ctag16 == NULL) {
5699cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                *outError = "failed to get XML element name (bad string pool)";
5709cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                return Vector<String8>();
5719cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            }
5729cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski            String8 tag(ctag16);
57394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
57494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (depth == 1) {
57594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == serviceTagName) {
57694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    withinApduService = true;
57794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
57894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            } else if (depth == 2 && withinApduService) {
57994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                if (tag == "aid-group") {
58094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    String8 category = getAttribute(tree, CATEGORY_ATTR, &error);
58194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (error != "") {
58294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (outError != NULL) *outError = error;
58394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        return Vector<String8>();
58494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
58594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
58694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    categories.add(category);
58794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                }
58894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
58994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski        }
59094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    }
59194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    aidAsset->close();
59294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski    return categories;
59394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski}
59494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
5959d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinskistatic void printComponentPresence(const char* componentName) {
5969d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski    printf("provides-component:'%s'\n", componentName);
5979d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski}
5989d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
5992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
6002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a feature that has been automatically added due to
6012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * a pre-requisite or some other reason.
6022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
6032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct ImpliedFeature {
6042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Name of the implied feature.
6062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name;
6082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6092c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * List of human-readable reasons for why this feature was implied.
6112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    SortedVector<String8> reasons;
6132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
6142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski/**
6162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski * Represents a <feature-group> tag in the AndroidManifest.xml
6172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski */
6182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistruct FeatureGroup {
619d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    FeatureGroup() : openGLESVersion(-1) {}
620d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
6212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Human readable label
6232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 label;
6252c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    /**
6272c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     * Explicit features defined in the group
6282c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski     */
6292c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    KeyedVector<String8, bool> features;
630d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
631d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    /**
632d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     * OpenGL ES version required
633d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski     */
634d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    int openGLESVersion;
6352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski};
6362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
6382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const char* name, const char* reason) {
6392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    String8 name8(name);
6402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    ssize_t idx = impliedFeatures->indexOfKey(name8);
6412c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (idx < 0) {
6422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        idx = impliedFeatures->add(name8, ImpliedFeature());
6432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        impliedFeatures->editValueAt(idx).name = name8;
6442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6452c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
6462c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6472c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void printFeatureGroup(const FeatureGroup& grp,
6492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
6502c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    printf("feature-group: label='%s'\n", grp.label.string());
6512c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
652d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    if (grp.openGLESVersion > 0) {
653d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
654d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    }
655d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
6562c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numFeatures = grp.features.size();
6572c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numFeatures; i++) {
6582c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (!grp.features[i]) {
6592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6602c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6612c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const String8& featureName = grp.features.keyAt(i);
6632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n",
6642c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                ResTable::normalizeForOutput(featureName.string()).string());
6652c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6662c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6672c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    const size_t numImpliedFeatures =
6682c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        (impliedFeatures != NULL) ? impliedFeatures->size() : 0;
6692c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    for (size_t i = 0; i < numImpliedFeatures; i++) {
6702c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const ImpliedFeature& impliedFeature = impliedFeatures->valueAt(i);
6712c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        if (grp.features.indexOfKey(impliedFeature.name) >= 0) {
6722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // The feature is explicitly set, no need to use implied
6732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            // definition.
6742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            continue;
6752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6772c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        String8 printableFeatureName(ResTable::normalizeForOutput(
6782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    impliedFeature.name.string()));
6792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-feature: name='%s'\n", printableFeatureName.string());
6802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("  uses-implied-feature: name='%s' reason='",
6812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printableFeatureName.string());
6822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        const size_t numReasons = impliedFeature.reasons.size();
6832c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        for (size_t j = 0; j < numReasons; j++) {
6842c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            printf("%s", impliedFeature.reasons[j].string());
6852c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (j + 2 < numReasons) {
6862c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", ");
6872c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else if (j + 1 < numReasons) {
6882c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printf(", and ");
6892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            }
6902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        }
6912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        printf("'\n");
6922c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
6932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
6942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
6952c72b6822debb08fe997926eedc110f62d287d34Adam Lesinskistatic void addParentFeatures(FeatureGroup* grp, const String8& name) {
6962c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    if (name == "android.hardware.camera.autofocus" ||
6972c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.camera.flash") {
6982c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.camera"), true);
6992c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.location.gps" ||
7002c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            name == "android.hardware.location.network") {
7012c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.location"), true);
7022c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch") {
7032c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
7042c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
7052c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen.multitouch"), true);
7062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski        grp->features.add(String8("android.hardware.touchscreen"), true);
707d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski    } else if (name == "android.hardware.opengles.aep") {
708d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        const int openGLESVersion31 = 0x00030001;
709d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        if (openGLESVersion31 > grp->openGLESVersion) {
710d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski            grp->openGLESVersion = openGLESVersion31;
711d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski        }
7122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski    }
7132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski}
7142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
737f85e41f29a0e9313c2d4725f9d9648591ea49f3bNarayan Kamath    int32_t assetsCookie;
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
74991447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath    memset(&config, 0, sizeof(ResTable_config));
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
760c2dea8daea2ae0001d56689d96ce1066012b7b40Adam Lesinski    config.screenLayout |= ResTable_config::SCREENSIZE_NORMAL;
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (&res == NULL) {
765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
76663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
76725e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski    } else if (res.getError() != NO_ERROR) {
76825e9d55e964c180ec6e57ba1d977d6c2e1115f5aAdam Lesinski        fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
76963e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        return 1;
77063e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    }
77163e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
7722cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // The dynamicRefTable can be null if there are no resources for this asset cookie.
7732cb761e3ddb9d68ab430013e9cd15ecaab9fbc62Adam Lesinski    // This fine.
77463e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie);
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski    Asset* asset = NULL;
77763e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
79563e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
79663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
82263e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER);
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82863e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski            ResXMLTree tree(dynamicRefTable);
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
84063e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER);
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
84663e646eed5a8d7f5d04544ac8628f65b0173cf3aAdam Lesinski        ResXMLTree tree(dynamicRefTable);
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
8679cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
8689cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
8699cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
8709cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
8719cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
8729cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
8802675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "permission") {
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
8882675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("permission: %s\n",
8892675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(name.string()).string());
890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "uses-permission") {
891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
89758f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(name,
89858f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
89958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
9250a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            bool isLeanbackLauncherActivity = false;
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
928ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
9292c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            bool withinFeatureGroup = false;
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
9329d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool withinProvider = false;
933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
9389d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasIntentFilter = false;
9399d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
942a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
943a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
945a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
94694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasPaymentService = false;
9479d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasDocumentsProvider = false;
9489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraActivity = false;
9499d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasCameraSecureActivity = false;
9509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasLauncher = false;
9519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasNotificationListenerService = false;
952eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasDreamService = false;
9539d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
956a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
959a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
960a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
96194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actHostApduService = false;
96294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool actOffHostApduService = false;
9639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actDocumentsProvider = false;
9649d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actNotificationListenerService = false;
965eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool actDreamService = false;
9669d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCamera = false;
9679d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool actCameraSecure = false;
9689d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool catLauncher = false;
96994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaHostPaymentCategory = false;
97094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasMetaOffHostPaymentCategory = false;
971a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
972a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
973a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
974a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
975a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
976a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
977a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
97894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            bool hasBindNfcServicePermission = false;
9799d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasRequiredSafAttributes = false;
9809d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            bool hasBindNotificationListenerServicePermission = false;
981eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            bool hasBindDreamServicePermission = false;
982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
997e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // If an app declares itself as multiArch, we report the
998e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            // native libraries differently.
999e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski            bool hasMultiArch = false;
1000e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
1005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
10062c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
1014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
1015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
1029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
10300a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn            String8 activityBanner;
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
1032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
1033ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
10342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
10352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            FeatureGroup commonFeatures;
10362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            Vector<FeatureGroup> featureGroups;
10372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            KeyedVector<String8, ImpliedFeature> impliedFeatures;
10382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
1042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
1043ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
1044ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
1045ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
1046ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
10472675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("%s", ResTable::normalizeForOutput(
10482675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        supportedInput[i].string()).string());
1049ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
1050ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
1051ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
1052ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
1053ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1054ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1055ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            supportedInput.clear();
1056ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        }
1057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = false;
1058ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = false;
10592c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = false;
1060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 3) {
10610a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        if (withinActivity && isMainActivity) {
10622675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            String8 aName(getComponentName(pkg, activityName));
10630a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLauncherActivity) {
10640a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("launchable-activity:");
10659eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
10669eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
10679eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
10680a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
10690a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s'\n",
10709eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
10719eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string());
10720a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
10730a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (isLeanbackLauncherActivity) {
10740a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf("leanback-launchable-activity:");
10759eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                if (aName.length() > 0) {
10769eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                    printf(" name='%s' ",
10779eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                            ResTable::normalizeForOutput(aName.string()).string());
10780a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                }
10790a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                printf(" label='%s' icon='%s' banner='%s'\n",
10809eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityLabel.string()).string(),
10819eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityIcon.string()).string(),
10829eaaaf0fe3917f4fec85d3e45da37914654847ecTim Kilbourn                                        ResTable::normalizeForOutput(activityBanner.string()).string());
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (!hasIntentFilter) {
1086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherActivities |= withinActivity;
1087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherReceivers |= withinReceiver;
1088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherServices |= withinService;
108994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        } else {
109094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (withinService) {
109194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
109294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
109394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
109494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        hasBindNfcServicePermission);
109594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
1096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinActivity = false;
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinService = false;
1099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinReceiver = false;
11009d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        withinProvider = false;
1101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasIntentFilter = false;
11020a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
1103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 4) {
1104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinIntentFilter) {
1105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (withinActivity) {
1106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMainActivity |= actMainActivity;
11079d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasLauncher |= catLauncher;
11089d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraActivity |= actCamera;
11099d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasCameraSecureActivity |= actCameraSecure;
11109d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinReceiver) {
1112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWidgetReceivers |= actWidgetReceivers;
1113a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
1114a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindDeviceAdminPermission);
1115a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
1116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinService) {
1117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasImeService |= actImeService;
1118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWallpaperService |= actWallpaperService;
1119a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasAccessibilityService |= (actAccessibilityService &&
1120a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindAccessibilityServicePermission);
1121a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
11229d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasNotificationListenerService |= actNotificationListenerService &&
11239d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        hasBindNotificationListenerServicePermission;
1124eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                hasDreamService |= actDreamService && hasBindDreamServicePermission;
1125a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherServices |= (!actImeService && !actWallpaperService &&
112694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        !actAccessibilityService && !actPrintService &&
11279d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actHostApduService && !actOffHostApduService &&
11289d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        !actNotificationListenerService);
11299d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (withinProvider) {
11309d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinIntentFilter = false;
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
1138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
1139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
11419cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski
11429cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                const char16_t* ctag16 = tree.getElementName(&len);
11439cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                if (ctag16 == NULL) {
11449cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
11459cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                    goto bail;
11469cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                }
11479cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                String8 tag(ctag16);
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d,  %s\n", depth, tag.string());
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
1150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
1151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    pkg = getAttribute(tree, NULL, "package", NULL);
11552675f769673f69b0661ddee346292f25cb30a296Maurice Chu                    printf("package: name='%s' ",
11562675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(pkg.string()).string());
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (versionCode > 0) {
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='%d' ", versionCode);
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='' ");
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
1168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
1169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
1170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
1171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
117225d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("versionName='%s'",
11732675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            ResTable::normalizeForOutput(versionName.string()).string());
117425d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski
117525d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    String8 splitName = getAttribute(tree, NULL, "split", NULL);
117625d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    if (!splitName.isEmpty()) {
117725d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                        printf(" split='%s'", ResTable::normalizeForOutput(
117825d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                                    splitName.string()).string());
117925d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    }
118025d35a9d68fed6304352d0bfc2e0d581ed47f8b5Adam Lesinski                    printf("\n");
1181caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski
1182caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    int32_t installLocation = getResolvedIntegerAttribute(&res, tree,
1183caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            INSTALL_LOCATION_ATTR, &error, -1);
1184caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    if (error != "") {
1185caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:installLocation' attribute: %s\n",
1186caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                error.string());
1187caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        goto bail;
1188caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    }
1189caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski
1190caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    if (installLocation >= 0) {
1191caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        printf("install-location:'");
1192caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        switch (installLocation) {
1193caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            case 0:
1194caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                printf("auto");
1195caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                break;
1196caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            case 1:
1197caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                printf("internalOnly");
1198caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                break;
1199caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            case 2:
1200caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                printf("preferExternal");
1201caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                break;
1202caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                            default:
1203caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                fprintf(stderr, "Invalid installLocation %d\n", installLocation);
1204caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                                goto bail;
1205caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        }
1206caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                        printf("'\n");
1207caf797c84a6a2829662872e0df93fcd61da78d51Adam Lesinski                    }
1208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2) {
1209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinApplication = false;
1210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag == "application") {
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = true;
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 label;
1214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t NL = locales.size();
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<NL; i++) {
1216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* localeStr =  locales[i].string();
1217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setLocale(localeStr != NULL ? localeStr : "");
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (llabel != "") {
1220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (localeStr == NULL || strlen(localeStr) == 0) {
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    label = llabel;
12222675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    printf("application-label:'%s'\n",
12232675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            ResTable::normalizeForOutput(llabel.string()).string());
1224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                } else {
1225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (label == "") {
1226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        label = llabel;
1227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label-%s:'%s'\n", localeStr,
12292675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                           ResTable::normalizeForOutput(llabel.string()).string());
1230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResTable_config tmpConfig = config;
1235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t ND = densities.size();
1236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<ND; i++) {
1237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            tmpConfig.density = densities[i];
1238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setConfiguration(tmpConfig);
1239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (icon != "") {
12412675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                printf("application-icon-%d:'%s'\n", densities[i],
12422675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(icon.string()).string());
1243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        assets.setConfiguration(config);
1246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
1250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
1253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
1255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
12572675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("application: label='%s' ",
12582675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                ResTable::normalizeForOutput(label.string()).string());
12592675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string());
1260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (testOnly != 0) {
1261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("testOnly='%d'\n", testOnly);
1262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
1265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (debuggable != 0) {
1270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("application-debuggable\n");
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1272e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
1273e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // We must search by name because the multiArch flag hasn't been API
1274e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // frozen yet.
1275e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        int32_t multiArchIndex = tree.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
1276e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                "multiArch");
1277e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (multiArchIndex >= 0) {
1278e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            Res_value value;
1279e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            if (tree.getAttributeValue(multiArchIndex, &value) != NO_ERROR) {
1280e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                if (value.dataType >= Res_value::TYPE_FIRST_INT &&
1281e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                        value.dataType <= Res_value::TYPE_LAST_INT) {
1282e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                    hasMultiArch = value.data;
1283e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                }
1284e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            }
1285e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
1286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-sdk") {
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
1293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut") targetSdk = 4;
12972675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("sdkVersion:'%s'\n",
12982675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            targetSdk = code;
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%d'\n", code);
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
1304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (code != -1) {
1305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("maxSdkVersion:'%d'\n", code);
1306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
1308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
1309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
1310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
1311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
1313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
1314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
13172675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("targetSdkVersion:'%s'\n",
13182675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
1320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (targetSdk < code) {
1321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                targetSdk = code;
1322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%d'\n", code);
1324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-configuration") {
1326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqTouchScreen = getIntegerAttribute(tree,
1327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
1328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqKeyboardType = getIntegerAttribute(tree,
1329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
1330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
1331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
1332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqNavigation = getIntegerAttribute(tree,
1333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_NAVIGATION_ATTR, NULL, 0);
1334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
1335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
1336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-configuration:");
1337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqTouchScreen != 0) {
1338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqTouchScreen='%d'", reqTouchScreen);
1339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqKeyboardType != 0) {
1341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqKeyboardType='%d'", reqKeyboardType);
1342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqHardKeyboard != 0) {
1344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
1345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqNavigation != 0) {
1347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqNavigation='%d'", reqNavigation);
1348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqFiveWayNav != 0) {
1350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
1351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("\n");
1353ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    } else if (tag == "supports-input") {
1354ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = true;
1355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-screens") {
1356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        smallScreen = getIntegerAttribute(tree,
1357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SMALL_SCREEN_ATTR, NULL, 1);
1358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        normalScreen = getIntegerAttribute(tree,
1359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                NORMAL_SCREEN_ATTR, NULL, 1);
1360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largeScreen = getIntegerAttribute(tree,
1361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGE_SCREEN_ATTR, NULL, 1);
1362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        xlargeScreen = getIntegerAttribute(tree,
1363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                XLARGE_SCREEN_ATTR, NULL, 1);
1364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        anyDensity = getIntegerAttribute(tree,
1365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                ANY_DENSITY_ATTR, NULL, 1);
1366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largestWidthLimitDp = getIntegerAttribute(tree,
1371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
13722c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (tag == "feature-group") {
13732c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        withinFeatureGroup = true;
13742c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        FeatureGroup group;
13752c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        group.label = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
13762c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (error != "") {
13772c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:label' attribute:"
13782c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    " %s\n", error.string());
13792c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            goto bail;
13802c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
13812c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        featureGroups.add(group);
13822c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-feature") {
1384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int req = getIntegerAttribute(tree,
1387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    REQUIRED_ATTR, NULL, 1);
1388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
13892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            commonFeatures.features.add(name, req);
13902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                            if (req) {
13912c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addParentFeatures(&commonFeatures, name);
1392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int vers = getIntegerAttribute(tree,
1395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    GL_ES_VERSION_ATTR, &error);
1396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error == "") {
1397d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > commonFeatures.openGLESVersion) {
1398d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.openGLESVersion = vers;
1399d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-permission") {
1403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.permission.CAMERA") {
1406d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.camera",
14072c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14082c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
14102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
14112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
14132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
14142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
14172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
14182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14192c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
14212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
14222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14232c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
14242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
14252c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14262c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
14292c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.location",
14302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.BLUETOOTH" ||
1433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.BLUETOOTH_ADMIN") {
14342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                if (targetSdk > 4) {
14352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
14362c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            String8::format("requested %s permission", name.string())
14372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            .string());
14382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
14392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "targetSdkVersion > 4");
14402c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                }
1441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.RECORD_AUDIO") {
14422c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
14432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14442c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
14482c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
14492c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8::format("requested %s permission", name.string())
14502c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        .string());
1451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.CALL_PHONE" ||
1452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CALL_PRIVILEGED" ||
1453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.READ_SMS" ||
1456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_SMS" ||
1457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_MMS" ||
1458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.SEND_SMS" ||
1460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_SMS") {
14622c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
14632c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                        String8("requested a telephony permission").string());
1464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteExternalStoragePermission = true;
1466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadExternalStoragePermission = true;
1468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_PHONE_STATE") {
1469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadPhoneStatePermission = true;
1470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CONTACTS") {
1471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadContactsPermission = true;
1472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CONTACTS") {
1473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteContactsPermission = true;
1474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CALL_LOG") {
1475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadCallLogPermission = true;
1476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteCallLogPermission = true;
1478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
147958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski
148058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            printUsesPermission(name,
148158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1) == 0,
148258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                                    getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1));
148358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                       } else {
1484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-package") {
1489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
14912675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("uses-package:'%s'\n",
14922675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "original-package") {
1499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
15012675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("original-package:'%s'\n",
15022675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-gl-texture") {
1509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
15112675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("supports-gl-texture:'%s'\n",
15122675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(name.string()).string());
1513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "compatible-screens") {
15199cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        printCompatibleScreens(tree, &error);
15209cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        if (error != "") {
15219cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
15229cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                                    error.string());
15239cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                            goto bail;
15249cb2c68fafce55d43aacb2202deb882b986fa237Adam Lesinski                        }
1525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        depth--;
1526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "package-verifier") {
1527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (publicKey != "" && error == "") {
1531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("package-verifier: name='%s' publicKey='%s'\n",
15322675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(name.string()).string(),
15332675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                        ResTable::normalizeForOutput(publicKey.string()).string());
1534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1537ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                } else if (depth == 3) {
1538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinActivity = false;
1539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinReceiver = false;
1540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinService = false;
15419d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    withinProvider = false;
1542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasIntentFilter = false;
154394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaHostPaymentCategory = false;
154494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasMetaOffHostPaymentCategory = false;
154594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindDeviceAdminPermission = false;
154694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindInputMethodPermission = false;
154794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindAccessibilityServicePermission = false;
154894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindPrintServicePermission = false;
154994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    hasBindNfcServicePermission = false;
15509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasRequiredSafAttributes = false;
15519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                    hasBindNotificationListenerServicePermission = false;
1552eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                    hasBindDreamServicePermission = false;
1553ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    if (withinApplication) {
1554ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if(tag == "activity") {
1555ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinActivity = true;
1556ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityName = getAttribute(tree, NAME_ATTR, &error);
1557ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1558ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1559ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1560ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1561ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1563ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1564ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1565ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1566ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1567ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1568ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1570ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1571ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1572ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1573ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1574ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1575ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
15770a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
15780a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            if (error != "") {
15790a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
15800a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                        error.string());
15810a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                goto bail;
15820a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            }
15830a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn
1584ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1585ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    SCREEN_ORIENTATION_ATTR, &error);
1586ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error == "") {
1587ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (orien == 0 || orien == 6 || orien == 8) {
1588ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests landscape, sensorLandscape, or reverseLandscape.
15892c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
15902c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "one or more activities have specified a landscape orientation");
1591ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else if (orien == 1 || orien == 7 || orien == 9) {
1592ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests portrait, sensorPortrait, or reversePortrait.
15932c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                    addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
15942c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                                            "one or more activities have specified a portrait orientation");
1595ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1597ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "uses-library") {
1598ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1599ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1600ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1601ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for uses-library"
1602ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1603ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1604ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1605ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int req = getIntegerAttribute(tree,
1606ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    REQUIRED_ATTR, NULL, 1);
1607ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("uses-library%s:'%s'\n",
16082675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    req ? "" : "-not-required", ResTable::normalizeForOutput(
16092675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                            libraryName.string()).string());
1610ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "receiver") {
1611ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinReceiver = true;
1612ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1614ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1615ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1616ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for receiver:"
1617ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1618ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1619ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1620a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1621a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1622a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1623a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1624a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindDeviceAdminPermission = true;
1625a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1626a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1627a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1628a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1629a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1630ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "service") {
1631ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinService = true;
1632ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1634ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1635ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1636ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "service:%s\n", error.string());
1637ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1638ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1639a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1640a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1641a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1642a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1643a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindInputMethodPermission = true;
1644a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1645a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindAccessibilityServicePermission = true;
1646a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1647a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindPrintServicePermission = true;
164894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else if (permission == "android.permission.BIND_NFC_SERVICE") {
164994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasBindNfcServicePermission = true;
16509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
16519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    hasBindNotificationListenerServicePermission = true;
1652eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                } else if (permission == "android.permission.BIND_DREAM_SERVICE") {
1653eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                    hasBindDreamServicePermission = true;
1654a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1655a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1656a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1657a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " service '%s': %s\n", serviceName.string(), error.string());
1658a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
16599d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (tag == "provider") {
16609d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            withinProvider = true;
16619d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16629d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            bool exported = getResolvedIntegerAttribute(&res, tree, EXPORTED_ATTR, &error);
16639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16649d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
16659d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16669d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16679d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16689d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16699d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            bool grantUriPermissions = getResolvedIntegerAttribute(&res, tree,
16709d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    GRANT_URI_PERMISSIONS_ATTR, &error);
16719d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16729d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
16739d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16749d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16759d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16769d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16779d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            String8 permission = getResolvedAttribute(&res, tree, PERMISSION_ATTR, &error);
16789d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (error != "") {
16799d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
16809d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                        " %s\n", error.string());
16819d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                goto bail;
16829d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
16839d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
16849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            hasRequiredSafAttributes |= exported && grantUriPermissions &&
16859d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                permission == "android.permission.MANAGE_DOCUMENTS";
16869d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
1687ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1688b71adb6571aa740f4fa794602133f708e1b96545Adam Lesinski                            String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1689ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1690ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1691ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1692ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1693ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
16942675f769673f69b0661ddee346292f25cb30a296Maurice Chu                            printf("meta-data: name='%s' ",
16952675f769673f69b0661ddee346292f25cb30a296Maurice Chu                                    ResTable::normalizeForOutput(metaDataName.string()).string());
169676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printResolvedResourceAttribute(&res, tree, VALUE_ATTR, String8("value"),
169776327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    &error);
1698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
169976327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                // Try looking for a RESOURCE_ATTR
170076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                error = "";
170176327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                printResolvedResourceAttribute(&res, tree, RESOURCE_ATTR,
170276327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                        String8("resource"), &error);
1703ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (error != "") {
170476327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                    fprintf(stderr, "ERROR getting 'android:value' or "
170576327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "'android:resource' attribute for "
170676327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                                            "meta-data:%s\n", error.string());
1707ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    goto bail;
1708ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1709ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
171076327314d2238e105f8b94909f9c0cf85caca318Maurice Chu                            printf("\n");
1711ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (withinSupportsInput && tag == "input-type") {
1712ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1713ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (name != "" && error == "") {
1714ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                supportedInput.add(name);
1715ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1716ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1717ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
17212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    } else if (withinFeatureGroup && tag == "uses-feature") {
1722d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        FeatureGroup& top = featureGroups.editTop();
1723d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
17242c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        String8 name = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
1725d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        if (name != "" && error == "") {
1726d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            top.features.add(name, true);
1727d3edfde51bd069a63e820282421d1a534fcf00ceAdam Lesinski                            addParentFeatures(&top, name);
1728d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        } else {
1729d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            int vers = getIntegerAttribute(tree, GL_ES_VERSION_ATTR, &error);
1730d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            if (error == "") {
1731d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                if (vers > top.openGLESVersion) {
1732d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    top.openGLESVersion = vers;
1733d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                }
1734d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            }
17352c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1736a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
173794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                } else if (depth == 4) {
173894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    if (tag == "intent-filter") {
173994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        hasIntentFilter = true;
174094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        withinIntentFilter = true;
174194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actMainActivity = false;
174294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWidgetReceivers = false;
174394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actImeService = false;
174494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actWallpaperService = false;
174594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actAccessibilityService = false;
174694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actPrintService = false;
174794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actDeviceAdminEnabled = false;
174894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actHostApduService = false;
174994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        actOffHostApduService = false;
17509d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actDocumentsProvider = false;
17519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actNotificationListenerService = false;
1752eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                        actDreamService = false;
17539d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCamera = false;
17549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        actCameraSecure = false;
17559d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        catLauncher = false;
175694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    } else if (withinService && tag == "meta-data") {
175794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
175894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (error != "") {
175994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute for"
176094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
176194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            goto bail;
176294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
176394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
176494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        if (name == "android.nfc.cardemulation.host_apdu_service" ||
176594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                name == "android.nfc.cardemulation.off_host_apdu_service") {
176694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            bool offHost = true;
176794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (name == "android.nfc.cardemulation.host_apdu_service") {
176894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                offHost = false;
176994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
177094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
177194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
177294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
177394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:resource' attribute for"
177494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
177594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
177694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
177794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
177894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
177994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    offHost, &error);
178094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            if (error != "") {
178194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                fprintf(stderr, "ERROR getting AID category for service '%s'\n",
178294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                        serviceName.string());
178394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                goto bail;
178494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
178594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski
178694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            const size_t catLen = categories.size();
178794fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            for (size_t i = 0; i < catLen; i++) {
178894fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                bool paymentCategory = (categories[i] == "payment");
178994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                if (offHost) {
179094fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaOffHostPaymentCategory |= paymentCategory;
179194fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                } else {
179294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                    hasMetaHostPaymentCategory |= paymentCategory;
179394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                }
179494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            }
179594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                        }
179694fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                    }
1797a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 5) && withinIntentFilter) {
1798a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    String8 action;
1799a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "action") {
1800a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        action = getAttribute(tree, NAME_ATTR, &error);
1801a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1802a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1803a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1804a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1805a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1806a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1807a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1808a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.intent.action.MAIN") {
1809a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isMainActivity = true;
1810a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actMainActivity = true;
18119d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA" ||
18129d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                    action == "android.media.action.VIDEO_CAMERA") {
18139d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCamera = true;
18149d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.media.action.STILL_IMAGE_CAMERA_SECURE") {
18159d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actCameraSecure = true;
1816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1817a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinReceiver) {
1818a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1819a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWidgetReceivers = true;
1820a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1821a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actDeviceAdminEnabled = true;
1822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1823a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinService) {
1824a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.view.InputMethod") {
1825a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actImeService = true;
1826a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.service.wallpaper.WallpaperService") {
1827a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWallpaperService = true;
1828a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.accessibilityservice.AccessibilityService") {
1829a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actAccessibilityService = true;
1830a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.printservice.PrintService") {
1831a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actPrintService = true;
183294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
183394fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actHostApduService = true;
183494fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                            } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
183594fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski                                actOffHostApduService = true;
18369d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (action == "android.service.notification.NotificationListenerService") {
18379d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actNotificationListenerService = true;
1838eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                            } else if (action == "android.service.dreams.DreamService") {
1839eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                                actDreamService = true;
18409d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            }
18419d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                        } else if (withinProvider) {
18429d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            if (action == "android.content.action.DOCUMENTS_PROVIDER") {
18439d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                actDocumentsProvider = true;
1844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1846a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (action == "android.intent.action.SEARCH") {
1847a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            isSearchable = true;
1848a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1849a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1851a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "category") {
1852a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        String8 category = getAttribute(tree, NAME_ATTR, &error);
1853a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1854a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1855a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1856a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1857a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1858a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1859a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (category == "android.intent.category.LAUNCHER") {
1860a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isLauncherActivity = true;
18610a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
18620a5a5d6996e54a927af750e122a1275d64f77ee5Tim Kilbourn                                isLeanbackLauncherActivity = true;
18639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                            } else if (category == "android.intent.category.HOME") {
18649d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                                catLauncher = true;
1865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-1.6 implicitly granted permission compatibility logic
1872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 4) {
1873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteExternalStoragePermission) {
187458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"));
187558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_EXTERNAL_STORAGE"),
187658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasWriteExternalStoragePermission = true;
1878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadPhoneStatePermission) {
188058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_PHONE_STATE"));
188158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_PHONE_STATE"),
188258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 4"));
1883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
1888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // do this (regardless of target API version) because we can't have
1889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // an app with write permission but not read permission.
1890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
189158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
189258f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
189358f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                        String8("requested WRITE_EXTERNAL_STORAGE"));
1894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-JellyBean call log permission compatibility.
1897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 16) {
1898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadCallLogPermission && hasReadContactsPermission) {
189958f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.READ_CALL_LOG"));
190058f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.READ_CALL_LOG"),
190158f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested READ_CONTACTS"));
1902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
190458f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesPermission(String8("android.permission.WRITE_CALL_LOG"));
190558f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                    printUsesImpliedPermission(String8("android.permission.WRITE_CALL_LOG"),
190658f1f3617cb6d96e3f3cf3d5c99004a362f0a61eAdam Lesinski                            String8("targetSdkVersion < 16 and requested WRITE_CONTACTS"));
1907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19102c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
19112c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    "default feature for all apps");
19122c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
19132c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            const size_t numFeatureGroups = featureGroups.size();
19142c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            if (numFeatureGroups == 0) {
19152c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // If no <feature-group> tags were defined, apply auto-implied features.
19162c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                printFeatureGroup(commonFeatures, &impliedFeatures);
19172c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
19182c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski            } else {
19192c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                // <feature-group> tags are defined, so we ignore implied features and
19202c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                for (size_t i = 0; i < numFeatureGroups; i++) {
19212c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    FeatureGroup& grp = featureGroups.editItemAt(i);
19222c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1923d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    if (commonFeatures.openGLESVersion > grp.openGLESVersion) {
1924d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                        grp.openGLESVersion = commonFeatures.openGLESVersion;
1925d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                    }
1926d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski
19272c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // Merge the features defined in the top level (not inside a <feature-group>)
19282c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    // with this feature group.
19292c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    const size_t numCommonFeatures = commonFeatures.features.size();
19302c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    for (size_t j = 0; j < numCommonFeatures; j++) {
19312c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        if (grp.features.indexOfKey(commonFeatures.features.keyAt(j)) < 0) {
1932d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                            grp.features.add(commonFeatures.features.keyAt(j),
1933d7a94da476e9b783acf0673ed938cc3fc2cc6ba5Adam Lesinski                                    commonFeatures.features[j]);
19342c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        }
1935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19372c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                   if (!grp.features.isEmpty()) {
19382c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                        printFeatureGroup(grp);
19392c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski                    }
1940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19432c72b6822debb08fe997926eedc110f62d287d34Adam Lesinski
1944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWidgetReceivers) {
19459d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("app-widget");
1946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1947a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasDeviceAdminReceiver) {
19489d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("device-admin");
1949a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasImeService) {
19519d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("ime");
1952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWallpaperService) {
19549d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("wallpaper");
1955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1956a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasAccessibilityService) {
19579d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("accessibility");
1958a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1959a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasPrintService) {
19609d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("print-service");
1961a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
196294fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            if (hasPaymentService) {
19639d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("payment");
19649d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19659d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (isSearchable) {
19669d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("search");
19679d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19689d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasDocumentsProvider) {
19699d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("document-provider");
19709d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19719d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasLauncher) {
19729d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("launcher");
19739d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19749d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasNotificationListenerService) {
19759d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("notification-listener");
19769d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
1977eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            if (hasDreamService) {
1978eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock                printComponentPresence("dream");
1979eb8d1be6acad180eabde84f19196b9ecaba81353John Spurlock            }
19809d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraActivity) {
19819d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera");
19829d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19839d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasCameraSecureActivity) {
19849d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printComponentPresence("camera-secure");
19859d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            }
19869d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski
19879d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski            if (hasMainActivity) {
19889d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski                printf("main\n");
198994fc9124f51f0a101cc11e4563f9c647980fe2aaAdam Lesinski            }
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherActivities) {
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-activities\n");
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
19939d5b08ea8c1eef6658418b33090a6a8142d75208Adam Lesinski             if (hasOtherReceivers) {
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-receivers\n");
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherServices) {
1997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-services\n");
1998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For modern apps, if screen size buckets haven't been specified
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // but the new width ranges have, then infer the buckets from them.
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
2003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    && requiresSmallestWidthDp > 0) {
2004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int compatWidth = compatibleWidthLimitDp;
2005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (compatWidth <= 0) {
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    compatWidth = requiresSmallestWidthDp;
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = -1;
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = 0;
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
2014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = -1;
2015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = 0;
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = -1;
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = 0;
2022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
2024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = -1;
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = 0;
2027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Determine default values for any unspecified screen sizes,
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // based on the target SDK of the package.  As of 4 (donut)
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the screen size support was introduced, so all default to
2033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // enabled.
2034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0) {
2035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                smallScreen = targetSdk >= 4 ? -1 : 0;
2036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen > 0) {
2038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                normalScreen = -1;
2039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen > 0) {
2041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                largeScreen = targetSdk >= 4 ? -1 : 0;
2042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen > 0) {
2044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Introduced in Gingerbread.
2045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                xlargeScreen = targetSdk >= 9 ? -1 : 0;
2046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (anyDensity > 0) {
2048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
2049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        || compatibleWidthLimitDp > 0) ? -1 : 0;
2050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-screens:");
2052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen != 0) {
2053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'small'");
2054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen != 0) {
2056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'normal'");
2057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen != 0) {
2059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'large'");
2060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen != 0) {
2062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'xlarge'");
2063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
2066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (requiresSmallestWidthDp > 0) {
2067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
2068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (compatibleWidthLimitDp > 0) {
2070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
2071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largestWidthLimitDp > 0) {
2073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
2074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("locales:");
2077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NL = locales.size();
2078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NL; i++) {
2079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const char* localeStr =  locales[i].string();
2080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localeStr == NULL || strlen(localeStr) == 0) {
2081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    localeStr = "--_--";
2082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'", localeStr);
2084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("densities:");
2088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t ND = densities.size();
2089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<ND; i++) {
2090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%d'", densities[i]);
2091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
2093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
2095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (dir != NULL) {
2096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dir->getFileCount() > 0) {
2097e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    SortedVector<String8> architectures;
2098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t i=0; i<dir->getFileCount(); i++) {
2099e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        architectures.add(ResTable::normalizeForOutput(
2100e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                                dir->getFileName(i).string()));
2101e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2102e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2103e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    bool outputAltNativeCode = false;
2104e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // A multiArch package is one that contains 64-bit and
2105e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit versions of native code and expects 3rd-party
2106e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // apps to load these native code libraries. Since most
2107e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 64-bit systems also support 32-bit apps, the apps
2108e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // loading this multiArch package's code may be either
2109e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    // 32-bit or 64-bit.
2110e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (hasMultiArch) {
2111e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If this is a multiArch package, report the 64-bit
2112e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // version only. Then as a separate entry, report the
2113e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // rest.
2114e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        //
2115e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // If we report the 32-bit architecture, this APK will
2116e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // be installed on a 32-bit device, causing a large waste
2117e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // of bandwidth and disk space. This assumes that
2118e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // the developer of the multiArch package has also
2119e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        // made a version that is 32-bit only.
2120e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 intel64("x86_64");
2121e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        String8 arm64("arm64-v8a");
2122e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        ssize_t index = architectures.indexOf(intel64);
2123e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index < 0) {
2124e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            index = architectures.indexOf(arm64);
2125e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2126e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2127e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (index >= 0) {
2128e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("native-code: '%s'\n", architectures[index].string());
2129e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            architectures.removeAt(index);
2130e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            outputAltNativeCode = true;
2131e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2132e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    }
2133e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski
2134e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    const size_t archCount = architectures.size();
2135e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                    if (archCount > 0) {
2136e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        if (outputAltNativeCode) {
2137e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf("alt-");
2138e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2139e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("native-code:");
2140e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        for (size_t i = 0; i < archCount; i++) {
2141e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                            printf(" '%s'", architectures[i].string());
2142e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        }
2143e47fd129057b19862e94b89f9ba413b5ceaca498Adam Lesinski                        printf("\n");
2144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                delete dir;
2147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badger", option) == 0) {
2149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s", CONSOLE_DATA);
2150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("configurations", option) == 0) {
2151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
2152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
2153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = configs.size();
2154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<N; i++) {
2155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("%s\n", configs[i].toString().string());
2156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
2159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (asset) {
2167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete asset;
2168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "add" command, which wants to add files to a new or
2175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * pre-existing archive.
2176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doAdd(Bundle* bundle)
2178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getUpdate()) {
2184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* avoid confusion */
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: can't use '-u' with add\n");
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, true);
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s'... (from gzip)\n", fileName);
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bundle->getJunkPath()) {
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 storageName = String8(fileName).getPathLeaf();
22152675f769673f69b0661ddee346292f25cb30a296Maurice Chu                printf(" '%s' as '%s'...\n", fileName,
22162675f769673f69b0661ddee346292f25cb30a296Maurice Chu                        ResTable::normalizeForOutput(storageName.string()).string());
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, storageName.string(),
2218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bundle->getCompressionMethod(), NULL);
2219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'...\n", fileName);
2221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
2226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result == NAME_NOT_FOUND) {
2227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": file not found\n");
2228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (result == ALREADY_EXISTS) {
2229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": already exists in archive\n");
2230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "\n");
2232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
2238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delete files from an existing archive.
2247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doRemove(Bundle* bundle)
2249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
2251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
2252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
2253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
2255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
2256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
2259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
2261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
2262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, false);
2266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
2267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
2268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zipFileName);
2269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
2273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
2274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* entry;
2275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByName(fileName);
2277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (entry == NULL) {
2278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s' NOT FOUND\n", fileName);
2279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = zip->remove(entry);
2283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
2285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
2286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                bundle->getFileSpecEntry(i), zipFileName);
2287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* update the archive */
2292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip->flush();
2293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
2296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
2297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
22993921e87e6e67a063caa1987937d7944b24aef489Adam Lesinskistatic status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
2300fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numDirs = dir->getDirs().size();
2301fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numDirs; i++) {
23023921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        bool ignore = ignoreConfig;
23033921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
23043921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        const char* dirStr = subDir->getLeaf().string();
23053921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
23063921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            ignore = true;
23073921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        }
23083921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski        status_t err = addResourcesToBuilder(subDir, builder, ignore);
2309fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        if (err != NO_ERROR) {
2310fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            return err;
2311fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2312fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2313fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2314fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    const size_t numFiles = dir->getFiles().size();
2315fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    for (size_t i = 0; i < numFiles; i++) {
2316fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
2317fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numConfigs = gp->getFiles().size();
2318fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t j = 0; j < numConfigs; j++) {
23193921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            status_t err = NO_ERROR;
23203921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            if (ignoreConfig) {
23213921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
23223921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            } else {
23233921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
23243921e87e6e67a063caa1987937d7944b24aef489Adam Lesinski            }
2325fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2326fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
2327fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
2328fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                return err;
2329fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2330fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2331fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2332fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return NO_ERROR;
2333fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2334fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2335fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinskistatic String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
2336fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (split->isBase()) {
2337fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return original;
2338fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2339fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2340fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    String8 ext(original.getPathExtension());
2341fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (ext == String8(".apk")) {
2342fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        return String8::format("%s_%s%s",
2343fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                original.getBasePath().string(),
2344fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                split->getDirectorySafeName().string(),
2345fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                ext.string());
2346fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2347fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2348fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    return String8::format("%s_%s", original.string(),
2349fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            split->getDirectorySafeName().string());
2350fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski}
2351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Package up an asset directory and associated application files.
2354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doPackage(Bundle* bundle)
2356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* outputAPKFile;
2358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int retVal = 1;
2359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
2360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptAssets> assets;
2361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int N;
2362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* fp;
2363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 dependencyFile;
2364fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<ApkBuilder> builder;
2365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2366a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    // -c en_XA or/and ar_XB means do pseudolocalization
2367fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
2368fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    err = configFilter->parse(bundle->getConfigurations());
2369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
2370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2372fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudo()) {
2373a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
2374a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    }
2375fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (configFilter->containsPseudoBidi()) {
2376a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
2377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    N = bundle->getFileSpecCount();
2380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
238109384303dea4f3f01d5682918d7bab9bf83a02b1Adam Lesinski            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
2382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no input files\n");
2383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outputAPKFile = bundle->getOutputAPKFile();
2387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make sure the filenames provided exist and are of the appropriate type.
2389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        FileType type;
2391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        type = getFileType(outputAPKFile);
2392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
2393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr,
2394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "ERROR: output file '%s' exists but is not regular file\n",
2395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outputAPKFile);
2396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Load the assets.
2401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets = new AaptAssets();
2402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Set up the resource gathering in assets if we're going to generate
2404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // dependency files. Every time we encounter a resource while slurping
2405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the tree, we'll add it to these stores so we have full resource paths
2406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to write to a dependency file.
2407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> resPathStore = new FilePathStore;
2409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullResPaths(resPathStore);
2410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> assetPathStore = new FilePathStore;
2411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullAssetPaths(assetPathStore);
2412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = assets->slurpFromArgs(bundle);
2415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
2420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->print(String8());
2421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2423fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // Create the ApkBuilder, which will collect the compiled files
2424fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // to write to the final APK (or sets of APKs if we are building
2425fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // a Split APK.
2426fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    builder = new ApkBuilder(configFilter);
2427fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2428fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    // If we are generating a Split APK, find out which configurations to split on.
2429fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    if (bundle->getSplitConfigurations().size() > 0) {
2430fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
2431fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splitStrs.size();
2432fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2433fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            std::set<ConfigDescription> configs;
2434fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
2435fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
2436fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2437fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2438fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2439fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = builder->createSplitForConfigs(configs);
2440fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2441fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2442fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2443fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2444fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    }
2445fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If they asked for any fileAs that need to be compiled, do so.
2447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
2448fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = buildResources(bundle, assets, builder);
2449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != 0) {
2450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At this point we've read everything and processed everything.  From here
2455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // on out it's just writing output files.
2456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Update symbols with information about which ones are needed as Java symbols.
2461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets->applyJavaSymbols();
2462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, do that here
2467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If this is the packaging step, generate the dependency file next to
2469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the output apk (e.g. bin/resources.ap_.d)
2470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outputAPKFile) {
2471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(outputAPKFile);
2472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Add the .d extension to the dependency file.
2473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.append(".d");
2474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Else if this is the R.java dependency generation step,
2476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // generate the dependency file in the R.java package subdirectory
2477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java.d
2478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(bundle->getRClassDir());
2479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.appendPath("R.java.d");
2480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Make sure we have a clean dependency file to start with
2482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "w");
2483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out R.java constants
2487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets->havePrivateSymbols()) {
2488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getCustomPackage() == NULL) {
2489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Write the R.java file into the appropriate class directory
2490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java
2491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
2492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String8 customPkg(bundle->getCustomPackage());
2494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, customPkg, true);
2495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If we have library files, we're going to write our R.java file into
2500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the appropriate class directory for those libraries as well.
2501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // e.g. gen/com/foo/app/lib/R.java
2502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getExtraPackages() != NULL) {
2503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Split on colon
2504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 libs(bundle->getExtraPackages());
2505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
2506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (packageString != NULL) {
2507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Write the R.java file out with the correct package name
2508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = writeResourceSymbols(bundle, assets, String8(packageString), true);
2509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < 0) {
2510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
2511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                packageString = strtok(NULL, ":");
2513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            libs.unlockBuffer();
2515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
2517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
2518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
2522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
2523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out the ProGuard file
2528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = writeProguardFile(bundle, assets);
2529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
2530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
2531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write the apk
2534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
2535fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // Gather all resources and add them to the APK Builder. The builder will then
2536fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        // figure out which Split they belong in.
2537fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        err = addResourcesToBuilder(assets, builder);
2538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
2539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
2540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2541fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski
2542fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
2543fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        const size_t numSplits = splits.size();
2544fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        for (size_t i = 0; i < numSplits; i++) {
2545fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            const sp<ApkSplit>& split = splits[i];
2546fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            String8 outputPath = buildApkName(String8(outputAPKFile), split);
2547fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            err = writeAPK(bundle, outputPath, split);
2548fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            if (err != NO_ERROR) {
2549fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
2550fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                goto bail;
2551fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            }
2552fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        }
2553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, we need to finish up here.
2556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the writeResourceSymbols and writeAPK functions have already written the target
2557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // half of the dependency file, now we need to write the prerequisites. (files that
2558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the R.java file or .ap_ file depend on)
2559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
2560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now that writeResourceSymbols or writeAPK has taken care of writing
2561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the targets to our dependency file, we'll write the prereqs
2562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "a+");
2563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, " : ");
2564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool includeRaw = (outputAPKFile != NULL);
2565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // and therefore was not added to our pathstores during slurping
2568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    retVal = 0;
2573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos::printErrors(stderr);
2576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retVal;
2578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching
2582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * PRECONDITIONS
2583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -S flag points to a source directory containing drawable* folders
2584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -C flag points to destination directory. The folder structure in the
2585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *     source directory will be mirrored to the destination (cache) directory
2586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * POSTCONDITIONS
2588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  Destination directory will be updated to match the PNG files in
25892675f769673f69b0661ddee346292f25cb30a296Maurice Chu *  the source directory.
2590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doCrunch(Bundle* bundle)
2592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching PNG Files in ");
2594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    updatePreProcessedCache(bundle);
2598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching on a single flag
2604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -i points to a single png file
2605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -o points to a single png output file
2606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doSingleCrunch(Bundle* bundle)
2608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 input(bundle->getSingleCrunchInputFile());
2613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 output(bundle->getSingleCrunchOutputFile());
2614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // we can't return the status_t as it gets truncate to the lower 8 bits.
2617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 42;
2618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskichar CONSOLE_DATA[2925] = {
2624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  };
2788