Command.cpp revision a5018c900f126ee8424c82497f32983873db741b
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Android Asset Packaging Tool main entry point.
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Main.h"
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Bundle.h"
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h"
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "Images.h"
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "XMLNode.h"
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Log.h>
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/threads.h>
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/List.h>
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/Errors.h>
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <fcntl.h>
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <errno.h>
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Show version info.  All the cool kids do it.
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doVersion(Bundle* bundle)
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 0) {
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("(ignoring extra arguments)\n");
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("Android Asset Packaging Tool, v0.2\n");
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read only.  The call fails if the file doesn't exist.
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadOnly(const char* fileName)
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip;
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, ZipFile::kOpenReadOnly);
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result == NAME_NOT_FOUND) {
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' not found\n", fileName);
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (result == PERMISSION_DENIED) {
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: '%s' access denied\n", fileName);
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: failed opening '%s' as Zip file\n",
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fileName);
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Open the file read-write.  The file will be created if it doesn't
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * already exist and "okayToCreate" is set.
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns NULL on failure.
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiZipFile* openReadWrite(const char* fileName, bool okayToCreate)
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result;
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int flags;
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    flags = ZipFile::kOpenReadWrite;
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (okayToCreate) {
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags |= ZipFile::kOpenCreate;
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = new ZipFile;
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = zip->open(fileName, flags);
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (result != NO_ERROR) {
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete zip;
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        zip = NULL;
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return zip;
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return a short string describing the compression method.
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char* compressionName(int method)
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (method == ZipEntry::kCompressStored) {
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Stored";
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (method == ZipEntry::kCompressDeflated) {
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Deflated";
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return "Unknown";
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Return the percent reduction in size (0% == no compression).
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint calcPercent(long uncompressedLen, long compressedLen)
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!uncompressedLen) {
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return (int) (100.0 - (compressedLen * 100.0) / uncompressedLen + 0.5);
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "list" command, which can be a simple file dump or
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * a verbose listing.
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The verbose listing closely matches the output of the Info-ZIP "unzip"
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * command.
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doList(Bundle* bundle)
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ZipEntry* entry;
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    long totalUncLen, totalCompLen;
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() != 1) {
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: specify zip file name (only)\n");
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadOnly(zipFileName);
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int count, i;
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Archive:  %s\n", zipFileName);
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            " Length   Method    Size  Ratio   Offset      Date  Time  CRC-32    Name\n");
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            "--------  ------  ------- -----  -------      ----  ----  ------    ----\n");
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    totalUncLen = totalCompLen = 0;
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    count = zip->getNumEntries();
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i = 0; i < count; i++) {
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByIndex(i);
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getVerbose()) {
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char dateBuf[32];
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            time_t when;
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            when = entry->getModWhen();
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            strftime(dateBuf, sizeof(dateBuf), "%m-%d-%y %H:%M",
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localtime(&when));
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%8ld  %-7.7s %7ld %3d%%  %8zd  %s  %08lx  %s\n",
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getUncompressedLen(),
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                compressionName(entry->getCompressionMethod()),
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (long) entry->getCompressedLen(),
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                calcPercent(entry->getUncompressedLen(),
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            entry->getCompressedLen()),
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (size_t) entry->getLFHOffset(),
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                dateBuf,
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getCRC32(),
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                entry->getFileName());
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s\n", entry->getFileName());
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalUncLen += entry->getUncompressedLen();
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        totalCompLen += entry->getCompressedLen();
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf(
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "--------          -------  ---                            -------\n");
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("%8ld          %7ld  %2d%%                            %d files\n",
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalUncLen,
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            totalCompLen,
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            calcPercent(totalUncLen, totalCompLen),
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zip->getNumEntries());
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getAndroidList()) {
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AssetManager assets;
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!assets.addAssetPath(String8(zipFileName), NULL)) {
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: list -a failed because assets could not be loaded\n");
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResTable& res = assets.getResources(false);
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (&res == NULL) {
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo resource table found.\n");
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nResource table:\n");
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.print(false);
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                   Asset::ACCESS_BUFFER);
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (manifestAsset == NULL) {
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nNo AndroidManifest.xml found.\n");
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\nAndroid manifest:\n");
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.setTo(manifestAsset->getBuffer(true),
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       manifestAsset->getLength());
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete manifestAsset;
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = 0;
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = tree.getAttributeCount();
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.getAttributeNameResID(i) == attrRes) {
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return (ssize_t)i;
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return -1;
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiString8 getAttribute(const ResXMLTree& tree, const char* ns,
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* attr, String8* outError)
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = tree.indexOfAttribute(ns, attr);
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const uint16_t* str = tree.getAttributeStringValue(idx, &len);
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8* outError, int32_t defValue = -1)
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError, int32_t defValue = -1)
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defValue;
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_REFERENCE) {
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(&value, 0);
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType < Res_value::TYPE_FIRST_INT
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || value.dataType > Res_value::TYPE_LAST_INT) {
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not an integer value";
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return defValue;
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value.data;
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t attrRes, String8* outError)
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String8();
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType == Res_value::TYPE_STRING) {
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const uint16_t* str = tree.getAttributeStringValue(idx, &len);
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return str ? String8(str, len) : String8();
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        resTable->resolveReference(&value, 0);
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value.dataType != Res_value::TYPE_STRING) {
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError != NULL) {
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                *outError = "attribute is not a string value";
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return String8();
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Res_value* value2 = &value;
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* str = const_cast<ResTable*>(resTable)->valueToString(value2, 0, NULL, &len);
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return str ? String8(str, len) : String8();
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void getResolvedResourceAttribute(Res_value* value, const ResTable* resTable,
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResXMLTree& tree, uint32_t attrRes, String8* outError)
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = indexOfAttribute(tree, attrRes);
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx < 0) {
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outError != NULL) {
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outError = "attribute could not be found";
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tree.getAttributeValue(idx, value) != NO_ERROR) {
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value->dataType == Res_value::TYPE_REFERENCE) {
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            resTable->resolveReference(value, 0);
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // The attribute was found and was resolved if need be.
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outError != NULL) {
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outError = "error getting resolved resource attribute";
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// These are attribute resource constants for the platform, as found
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// in android.R.attr
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskienum {
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LABEL_ATTR = 0x01010001,
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ICON_ATTR = 0x01010002,
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NAME_ATTR = 0x01010003,
387a5018c900f126ee8424c82497f32983873db741bAdam Lesinski    PERMISSION_ATTR = 0x01010006,
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DEBUGGABLE_ATTR = 0x0101000f,
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VALUE_ATTR = 0x01010024,
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_CODE_ATTR = 0x0101021b,
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    VERSION_NAME_ATTR = 0x0101021c,
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_ORIENTATION_ATTR = 0x0101001e,
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MIN_SDK_VERSION_ATTR = 0x0101020c,
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    MAX_SDK_VERSION_ATTR = 0x01010271,
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_TOUCH_SCREEN_ATTR = 0x01010227,
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_HARD_KEYBOARD_ATTR = 0x01010229,
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_NAVIGATION_ATTR = 0x0101022a,
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TARGET_SDK_VERSION_ATTR = 0x01010270,
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    TEST_ONLY_ATTR = 0x01010272,
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ANY_DENSITY_ATTR = 0x0101026c,
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    GL_ES_VERSION_ATTR = 0x01010281,
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SMALL_SCREEN_ATTR = 0x01010284,
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    NORMAL_SCREEN_ATTR = 0x01010285,
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGE_SCREEN_ATTR = 0x01010286,
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    XLARGE_SCREEN_ATTR = 0x010102bf,
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRED_ATTR = 0x0101028e,
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_SIZE_ATTR = 0x010102ca,
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    SCREEN_DENSITY_ATTR = 0x010102cb,
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    REQUIRES_SMALLEST_WIDTH_DP_ATTR = 0x01010364,
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PUBLIC_KEY_ATTR = 0x010103a6,
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst char *getComponentName(String8 &pkgName, String8 &componentName) {
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t idx = componentName.find(".");
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 retStr(pkgName);
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (idx == 0) {
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (idx < 0) {
423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += ".";
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retStr += componentName;
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return componentName.string();
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retStr.string();
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void printCompatibleScreens(ResXMLTree& tree) {
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int depth = 0;
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("compatible-screens:");
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::END_TAG) {
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            depth--;
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (depth < 0) {
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code != ResXMLTree::START_TAG) {
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        depth++;
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String8 tag(tree.getElementName(&len));
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tag == "screen") {
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenSize = getIntegerAttribute(tree,
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_SIZE_ATTR, NULL, -1);
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t screenDensity = getIntegerAttribute(tree,
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SCREEN_DENSITY_ATTR, NULL, -1);
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (screenSize > 0 && screenDensity > 0) {
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!first) {
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf(",");
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                first = false;
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("'%d/%d'", screenSize, screenDensity);
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("\n");
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "dump" command, to extract select data from an archive.
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiextern char CONSOLE_DATA[2925]; // see EOF
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doDump(Bundle* bundle)
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Asset* asset = NULL;
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump option specified\n");
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no dump file specified\n");
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* option = bundle->getFileSpecEntry(0);
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* filename = bundle->getFileSpecEntry(1);
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    AssetManager assets;
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    void* assetsCookie;
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 1;
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make a dummy config for retrieving resources...  we need to supply
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // non-default values for some configs so that we can retrieve resources
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // in the app that don't have a default.  The most important of these is
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the API version because key resources like icons will have an implicit
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // version if they are using newer config types like density.
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config config;
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[0] = 'e';
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.language[1] = 'n';
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[0] = 'U';
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.country[1] = 'S';
506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.orientation = ResTable_config::ORIENTATION_PORT;
507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.density = ResTable_config::DENSITY_MEDIUM;
508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.sdkVersion = 10000; // Very high.
509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenWidthDp = 320;
510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.screenHeightDp = 480;
511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    config.smallestScreenWidthDp = 320;
512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets.setConfiguration(config);
513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ResTable& res = assets.getResources(false);
515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (&res == NULL) {
516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp("resources", option) == 0) {
521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#ifndef HAVE_ANDROID_OS
522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res.print(bundle->getValues());
523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("strings", option) == 0) {
526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const ResStringPool* pool = res.getTableStringBlock(0);
527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printStringPool(pool);
528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmltree", option) == 0) {
530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.restart();
550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printXMLBlock(&tree);
551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tree.uninit();
552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (strcmp("xmlstrings", option) == 0) {
557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getFileSpecCount() < 3) {
558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i=2; i<bundle->getFileSpecCount(); i++) {
563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* resname = bundle->getFileSpecEntry(i);
564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree tree;
565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (asset == NULL) {
567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (tree.setTo(asset->getBuffer(true),
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           asset->getLength()) != NO_ERROR) {
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname);
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printStringPool(&tree.getStrings());
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            delete asset;
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            asset = NULL;
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResXMLTree tree;
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        asset = assets.openNonAsset("AndroidManifest.xml",
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            Asset::ACCESS_BUFFER);
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (asset == NULL) {
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n");
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (tree.setTo(asset->getBuffer(true),
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       asset->getLength()) != NO_ERROR) {
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n");
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.restart();
596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcmp("permissions", option) == 0) {
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 tag(tree.getElementName(&len));
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d tag %s\n", depth, tag.string());
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 pkg = getAttribute(tree, NULL, "package", NULL);
618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("package: %s\n", pkg.string());
619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "permission") {
620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("permission: %s\n", name.string());
627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2 && tag == "uses-permission") {
628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 error;
629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 name = getAttribute(tree, NAME_ATTR, &error);
630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: %s\n", error.string());
632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-permission: %s\n", name.string());
635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!req) {
637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("optional-permission: %s\n", name.string());
638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badging", option) == 0) {
642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<String8> locales;
643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getLocales(&locales);
644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SortedVector<int> densities;
648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = configs.size();
649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NC; i++) {
650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int dens = configs[i].density;
651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dens == 0) {
652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    dens = 160;
653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                densities.add(dens);
655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree::event_code_t code;
659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int depth = 0;
660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 error;
661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinActivity = false;
662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isMainActivity = false;
663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isLauncherActivity = false;
664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool isSearchable = false;
665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinApplication = false;
666ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            bool withinSupportsInput = false;
667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinReceiver = false;
668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinService = false;
669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool withinIntentFilter = false;
670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMainActivity = false;
671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherActivities = false;
672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherReceivers = false;
673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasOtherServices = false;
674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWallpaperService = false;
675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasImeService = false;
676a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasAccessibilityService = false;
677a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasPrintService = false;
678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWidgetReceivers = false;
679a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasDeviceAdminReceiver = false;
680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasIntentFilter = false;
681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actMainActivity = false;
682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWidgetReceivers = false;
683a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actDeviceAdminEnabled = false;
684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actImeService = false;
685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool actWallpaperService = false;
686a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actAccessibilityService = false;
687a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool actPrintService = false;
688a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
689a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // These permissions are required by services implementing services
690a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            // the system binds to (IME, Accessibility, PrintServices, etc.)
691a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindDeviceAdminPermission = false;
692a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindInputMethodPermission = false;
693a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindAccessibilityServicePermission = false;
694a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            bool hasBindPrintServicePermission = false;
695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // These two implement the implicit permissions that are granted
697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to pre-1.6 applications.
698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteExternalStoragePermission = false;
699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadPhoneStatePermission = false;
700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If an app requests write storage, they will also get read storage.
702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadExternalStoragePermission = false;
703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Implement transition to read and write call log.
705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadContactsPermission = false;
706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteContactsPermission = false;
707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasReadCallLogPermission = false;
708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWriteCallLogPermission = false;
709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This next group of variables is used to implement a group of
711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // backward-compatibility heuristics necessitated by the addition of
712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // heuristic is "if an app requests a permission but doesn't explicitly
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // request the corresponding <uses-feature>, presume it's there anyway".
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specCameraFeature = false; // camera-related
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specCameraAutofocusFeature = false;
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqCameraAutofocusFeature = false;
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqCameraFlashFeature = false;
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasCameraPermission = false;
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specLocationFeature = false; // location-related
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specNetworkLocFeature = false;
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqNetworkLocFeature = false;
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specGpsFeature = false;
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqGpsFeature = false;
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasMockLocPermission = false;
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasCoarseLocPermission = false;
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasGpsPermission = false;
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasGeneralLocPermission = false;
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specBluetoothFeature = false; // Bluetooth API-related
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasBluetoothPermission = false;
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specMicrophoneFeature = false; // microphone-related
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasRecordAudioPermission = false;
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specWiFiFeature = false;
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasWiFiPermission = false;
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specTelephonyFeature = false; // telephony-related
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqTelephonySubFeature = false;
737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool hasTelephonyPermission = false;
738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specTouchscreenFeature = false; // touchscreen-related
739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specMultitouchFeature = false;
740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqDistinctMultitouchFeature = false;
741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specScreenPortraitFeature = false;
742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool specScreenLandscapeFeature = false;
743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqScreenPortraitFeature = false;
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool reqScreenLandscapeFeature = false;
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // 2.2 also added some other features that apps can request, but that
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // have no corresponding permission, so we cannot implement any
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // back-compatibility heuristic for them. The below are thus unnecessary
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // (but are retained here for documentary purposes.)
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specCompassFeature = false;
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAccelerometerFeature = false;
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specProximityFeature = false;
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specAmbientLightFeature = false;
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //bool specLiveWallpaperFeature = false;
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int targetSdk = 0;
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int smallScreen = 1;
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int normalScreen = 1;
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largeScreen = 1;
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int xlargeScreen = 1;
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int anyDensity = 1;
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int requiresSmallestWidthDp = 0;
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int compatibleWidthLimitDp = 0;
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int largestWidthLimitDp = 0;
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 pkg;
765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityName;
766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityLabel;
767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 activityIcon;
768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 receiverName;
769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 serviceName;
770ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright            Vector<String8> supportedInput;
771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code == ResXMLTree::END_TAG) {
773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    depth--;
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (depth < 2) {
775ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if (withinSupportsInput && !supportedInput.isEmpty()) {
776ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("supports-input: '");
777ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            const size_t N = supportedInput.size();
778ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            for (size_t i=0; i<N; i++) {
779ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                printf("%s", supportedInput[i].string());
780ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (i != N - 1) {
781ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("' '");
782ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else {
783ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    printf("'\n");
784ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
785ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
786ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            supportedInput.clear();
787ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        }
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = false;
789ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = false;
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 3) {
791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinActivity && isMainActivity && isLauncherActivity) {
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char *aName = getComponentName(pkg, activityName);
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("launchable-activity:");
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (aName != NULL) {
795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf(" name='%s' ", aName);
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" label='%s' icon='%s'\n",
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    activityLabel.string(),
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    activityIcon.string());
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (!hasIntentFilter) {
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherActivities |= withinActivity;
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherReceivers |= withinReceiver;
804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasOtherServices |= withinService;
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinActivity = false;
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinService = false;
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinReceiver = false;
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasIntentFilter = false;
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        isMainActivity = isLauncherActivity = false;
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (depth < 4) {
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (withinIntentFilter) {
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (withinActivity) {
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMainActivity |= actMainActivity;
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasOtherActivities |= !actMainActivity;
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinReceiver) {
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWidgetReceivers |= actWidgetReceivers;
818a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
819a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindDeviceAdminPermission);
820a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (withinService) {
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasImeService |= actImeService;
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWallpaperService |= actWallpaperService;
824a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasAccessibilityService |= (actAccessibilityService &&
825a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        hasBindAccessibilityServicePermission);
826a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasPrintService |= (actPrintService && hasBindPrintServicePermission);
827a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                hasOtherServices |= (!actImeService && !actWallpaperService &&
828a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        !actAccessibilityService && !actPrintService);
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinIntentFilter = false;
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (code != ResXMLTree::START_TAG) {
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                depth++;
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 tag(tree.getElementName(&len));
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Depth %d,  %s\n", depth, tag.string());
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (depth == 1) {
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag != "manifest") {
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    pkg = getAttribute(tree, NULL, "package", NULL);
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("package: name='%s' ", pkg.string());
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int32_t versionCode = getIntegerAttribute(tree, VERSION_CODE_ATTR, &error);
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionCode' attribute: %s\n", error.string());
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (versionCode > 0) {
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='%d' ", versionCode);
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("versionCode='' ");
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8 versionName = getResolvedAttribute(&res, tree, VERSION_NAME_ATTR, &error);
859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (error != "") {
860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(stderr, "ERROR getting 'android:versionName' attribute: %s\n", error.string());
861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        goto bail;
862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("versionName='%s'\n", versionName.string());
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (depth == 2) {
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinApplication = false;
866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (tag == "application") {
867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        withinApplication = true;
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 label;
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t NL = locales.size();
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<NL; i++) {
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            const char* localeStr =  locales[i].string();
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setLocale(localeStr != NULL ? localeStr : "");
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 llabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (llabel != "") {
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (localeStr == NULL || strlen(localeStr) == 0) {
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    label = llabel;
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label:'%s'\n", llabel.string());
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                } else {
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (label == "") {
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        label = llabel;
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    printf("application-label-%s:'%s'\n", localeStr,
884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            llabel.string());
885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResTable_config tmpConfig = config;
890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const size_t ND = densities.size();
891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t i=0; i<ND; i++) {
892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            tmpConfig.density = densities[i];
893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            assets.setConfiguration(tmpConfig);
894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (icon != "") {
896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("application-icon-%d:'%s'\n", densities[i], icon.string());
897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        assets.setConfiguration(config);
900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 icon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("application: label='%s' ", label.string());
912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("icon='%s'\n", icon.string());
913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (testOnly != 0) {
914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("testOnly='%d'\n", testOnly);
915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t debuggable = getResolvedIntegerAttribute(&res, tree, DEBUGGABLE_ATTR, &error, 0);
918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:debuggable' attribute: %s\n", error.string());
920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (debuggable != 0) {
923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("application-debuggable\n");
924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-sdk") {
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut") targetSdk = 4;
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%s'\n", name.string());
937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            targetSdk = code;
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("sdkVersion:'%d'\n", code);
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (code != -1) {
943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("maxSdkVersion:'%d'\n", code);
944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (error != "") {
947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            error = "";
948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        error.string());
952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "Donut" && targetSdk < 4) targetSdk = 4;
955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%s'\n", name.string());
956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (code != -1) {
957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (targetSdk < code) {
958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                targetSdk = code;
959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("targetSdkVersion:'%d'\n", code);
961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-configuration") {
963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqTouchScreen = getIntegerAttribute(tree,
964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_TOUCH_SCREEN_ATTR, NULL, 0);
965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqKeyboardType = getIntegerAttribute(tree,
966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqHardKeyboard = getIntegerAttribute(tree,
968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_HARD_KEYBOARD_ATTR, NULL, 0);
969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqNavigation = getIntegerAttribute(tree,
970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_NAVIGATION_ATTR, NULL, 0);
971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t reqFiveWayNav = getIntegerAttribute(tree,
972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-configuration:");
974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqTouchScreen != 0) {
975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqTouchScreen='%d'", reqTouchScreen);
976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqKeyboardType != 0) {
978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqKeyboardType='%d'", reqKeyboardType);
979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqHardKeyboard != 0) {
981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqHardKeyboard='%d'", reqHardKeyboard);
982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqNavigation != 0) {
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqNavigation='%d'", reqNavigation);
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (reqFiveWayNav != 0) {
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf(" reqFiveWayNav='%d'", reqFiveWayNav);
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("\n");
990ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    } else if (tag == "supports-input") {
991ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        withinSupportsInput = true;
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-screens") {
993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        smallScreen = getIntegerAttribute(tree,
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SMALL_SCREEN_ATTR, NULL, 1);
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        normalScreen = getIntegerAttribute(tree,
996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                NORMAL_SCREEN_ATTR, NULL, 1);
997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largeScreen = getIntegerAttribute(tree,
998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGE_SCREEN_ATTR, NULL, 1);
999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        xlargeScreen = getIntegerAttribute(tree,
1000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                XLARGE_SCREEN_ATTR, NULL, 1);
1001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        anyDensity = getIntegerAttribute(tree,
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                ANY_DENSITY_ATTR, NULL, 1);
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        requiresSmallestWidthDp = getIntegerAttribute(tree,
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                REQUIRES_SMALLEST_WIDTH_DP_ATTR, NULL, 0);
1005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        compatibleWidthLimitDp = getIntegerAttribute(tree,
1006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                COMPATIBLE_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        largestWidthLimitDp = getIntegerAttribute(tree,
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                LARGEST_WIDTH_LIMIT_DP_ATTR, NULL, 0);
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-feature") {
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int req = getIntegerAttribute(tree,
1014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    REQUIRED_ATTR, NULL, 1);
1015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.hardware.camera") {
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specCameraFeature = true;
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.camera.autofocus") {
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // these have no corresponding permission to check for,
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // but should imply the foundational camera permission
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqCameraAutofocusFeature = reqCameraAutofocusFeature || req;
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specCameraAutofocusFeature = true;
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (req && (name == "android.hardware.camera.flash")) {
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // these have no corresponding permission to check for,
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // but should imply the foundational camera permission
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqCameraFlashFeature = true;
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.location") {
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specLocationFeature = true;
1029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.location.network") {
1030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specNetworkLocFeature = true;
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqNetworkLocFeature = reqNetworkLocFeature || req;
1032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.location.gps") {
1033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specGpsFeature = true;
1034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqGpsFeature = reqGpsFeature || req;
1035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.bluetooth") {
1036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specBluetoothFeature = true;
1037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.touchscreen") {
1038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specTouchscreenFeature = true;
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.touchscreen.multitouch") {
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specMultitouchFeature = true;
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
1042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req;
1043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.microphone") {
1044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specMicrophoneFeature = true;
1045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.wifi") {
1046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specWiFiFeature = true;
1047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.telephony") {
1048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specTelephonyFeature = true;
1049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (req && (name == "android.hardware.telephony.gsm" ||
1050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                               name == "android.hardware.telephony.cdma")) {
1051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // these have no corresponding permission to check for,
1052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // but should imply the foundational telephony permission
1053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                reqTelephonySubFeature = true;
1054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.screen.portrait") {
1055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specScreenPortraitFeature = true;
1056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.hardware.screen.landscape") {
1057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                specScreenLandscapeFeature = true;
1058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("uses-feature%s:'%s'\n",
1060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    req ? "" : "-not-required", name.string());
1061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int vers = getIntegerAttribute(tree,
1063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    GL_ES_VERSION_ATTR, &error);
1064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error == "") {
1065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("uses-gl-es:'0x%x'\n", vers);
1066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-permission") {
1069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (name == "android.permission.CAMERA") {
1072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasCameraPermission = true;
1073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
1074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasGpsPermission = true;
1075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
1076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasMockLocPermission = true;
1077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
1078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasCoarseLocPermission = true;
1079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
1080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
1081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasGeneralLocPermission = true;
1082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.BLUETOOTH" ||
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.BLUETOOTH_ADMIN") {
1084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasBluetoothPermission = true;
1085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.RECORD_AUDIO") {
1086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasRecordAudioPermission = true;
1087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
1088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_STATE" ||
1089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
1090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWiFiPermission = true;
1091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.CALL_PHONE" ||
1092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.CALL_PRIVILEGED" ||
1093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.MODIFY_PHONE_STATE" ||
1094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
1095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.READ_SMS" ||
1096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_SMS" ||
1097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_MMS" ||
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
1099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.SEND_SMS" ||
1100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_APN_SETTINGS" ||
1101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       name == "android.permission.WRITE_SMS") {
1102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasTelephonyPermission = true;
1103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
1104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteExternalStoragePermission = true;
1105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
1106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadExternalStoragePermission = true;
1107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_PHONE_STATE") {
1108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadPhoneStatePermission = true;
1109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CONTACTS") {
1110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadContactsPermission = true;
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CONTACTS") {
1112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteContactsPermission = true;
1113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.READ_CALL_LOG") {
1114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasReadCallLogPermission = true;
1115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else if (name == "android.permission.WRITE_CALL_LOG") {
1116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasWriteCallLogPermission = true;
1117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("uses-permission:'%s'\n", name.string());
1119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
1120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (!req) {
1121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("optional-permission:'%s'\n", name.string());
1122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            goto bail;
1127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "uses-package") {
1129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("uses-package:'%s'\n", name.string());
1132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "original-package") {
1138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("original-package:'%s'\n", name.string());
1141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "supports-gl-texture") {
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            printf("supports-gl-texture:'%s'\n", name.string());
1150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    error.string());
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "compatible-screens") {
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printCompatibleScreens(tree);
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        depth--;
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (tag == "package-verifier") {
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 name = getAttribute(tree, NAME_ATTR, &error);
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (name != "" && error == "") {
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8 publicKey = getAttribute(tree, PUBLIC_KEY_ATTR, &error);
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (publicKey != "" && error == "") {
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                printf("package-verifier: name='%s' publicKey='%s'\n",
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        name.string(), publicKey.string());
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1168ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                } else if (depth == 3) {
1169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinActivity = false;
1170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinReceiver = false;
1171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    withinService = false;
1172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasIntentFilter = false;
1173ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                    if (withinApplication) {
1174ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        if(tag == "activity") {
1175ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinActivity = true;
1176ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityName = getAttribute(tree, NAME_ATTR, &error);
1177ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1178ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1179ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1180ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1181ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1183ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityLabel = getResolvedAttribute(&res, tree, LABEL_ATTR, &error);
1184ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1185ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:label' attribute: %s\n",
1186ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1187ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1188ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1190ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            activityIcon = getResolvedAttribute(&res, tree, ICON_ATTR, &error);
1191ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1192ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n",
1193ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1194ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1195ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1197ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int32_t orien = getResolvedIntegerAttribute(&res, tree,
1198ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    SCREEN_ORIENTATION_ATTR, &error);
1199ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error == "") {
1200ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (orien == 0 || orien == 6 || orien == 8) {
1201ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests landscape, sensorLandscape, or reverseLandscape.
1202ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    reqScreenLandscapeFeature = true;
1203ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                } else if (orien == 1 || orien == 7 || orien == 9) {
1204ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    // Requests portrait, sensorPortrait, or reversePortrait.
1205ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    reqScreenPortraitFeature = true;
1206ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1208ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "uses-library") {
1209ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
1210ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1211ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1212ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for uses-library"
1213ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1214ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1215ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1216ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            int req = getIntegerAttribute(tree,
1217ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    REQUIRED_ATTR, NULL, 1);
1218ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("uses-library%s:'%s'\n",
1219ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    req ? "" : "-not-required", libraryName.string());
1220ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "receiver") {
1221ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinReceiver = true;
1222ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            receiverName = getAttribute(tree, NAME_ATTR, &error);
1223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1224ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1225ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr,
1226ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "ERROR getting 'android:name' attribute for receiver:"
1227ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        " %s\n", error.string());
1228ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1229ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1230a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1231a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1232a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1233a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_DEVICE_ADMIN") {
1234a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindDeviceAdminPermission = true;
1235a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1236a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1237a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1238a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " receiver '%s': %s\n", receiverName.string(), error.string());
1239a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1240ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (tag == "service") {
1241ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            withinService = true;
1242ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            serviceName = getAttribute(tree, NAME_ATTR, &error);
1243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1244ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1245ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1246ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "service:%s\n", error.string());
1247ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1248ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1249a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1250a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
1251a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (error == "") {
1252a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                if (permission == "android.permission.BIND_INPUT_METHOD") {
1253a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindInputMethodPermission = true;
1254a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
1255a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindAccessibilityServicePermission = true;
1256a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
1257a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    hasBindPrintServicePermission = true;
1258a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                }
1259a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else {
1260a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                fprintf(stderr, "ERROR getting 'android:permission' attribute for"
1261a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                        " service '%s': %s\n", serviceName.string(), error.string());
1262a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            }
1263ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
1264ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 metaDataName = getAttribute(tree, NAME_ATTR, &error);
1265ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (error != "") {
1266ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute for "
1267ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1268ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1269ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1270ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            printf("meta-data: name='%s' ", metaDataName.string());
1271ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            Res_value value;
1272ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            getResolvedResourceAttribute(&value, &res, tree, VALUE_ATTR, &error);
1273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (error != "") {
1274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                fprintf(stderr, "ERROR getting 'android:value' attribute for "
1275ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        "meta-data:%s\n", error.string());
1276ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                goto bail;
1277ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1278ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (value.dataType == Res_value::TYPE_STRING) {
1279ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                String8 metaDataValue = getAttribute(tree, value.data, &error);
1280ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                if (error != "") {
1281ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    fprintf(stderr, "ERROR getting 'android:value' attribute for "
1282ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                            "meta-data: %s\n", error.string());
1283ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    goto bail;
1284ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                }
1285ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                printf("value='%s'\n", metaDataValue.string());
1286ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
1287ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                    value.dataType <= Res_value::TYPE_LAST_INT) {
1288ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                printf("value='%d'\n", value.data);
1289ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1290ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                printf("value=(type 0x%x)0x%x",
1291ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        (int)value.dataType, (int)value.data);
1292ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            }
1293ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                        } else if (withinSupportsInput && tag == "input-type") {
1294ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            String8 name = getAttribute(tree, NAME_ATTR, &error);
1295ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            if (name != "" && error == "") {
1296ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                supportedInput.add(name);
1297ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                            } else {
1298ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1299ec4fdec76f2916b91a69d979f400cd69a3812631Michael Wright                                        error.string());
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                goto bail;
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1303a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1304a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 4) && (tag == "intent-filter")) {
1305a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    hasIntentFilter = true;
1306a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    withinIntentFilter = true;
1307a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actMainActivity = false;
1308a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actWidgetReceivers = false;
1309a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actImeService = false;
1310a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actWallpaperService = false;
1311a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actAccessibilityService = false;
1312a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actPrintService = false;
1313a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    actDeviceAdminEnabled = false;
1314a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                } else if ((depth == 5) && withinIntentFilter) {
1315a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    String8 action;
1316a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "action") {
1317a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        action = getAttribute(tree, NAME_ATTR, &error);
1318a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1319a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
1320a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1321a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1322a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1323a5018c900f126ee8424c82497f32983873db741bAdam Lesinski
1324a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1325a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.intent.action.MAIN") {
1326a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isMainActivity = true;
1327a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actMainActivity = true;
1328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1329a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinReceiver) {
1330a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
1331a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWidgetReceivers = true;
1332a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
1333a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actDeviceAdminEnabled = true;
1334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1335a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        } else if (withinService) {
1336a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (action == "android.view.InputMethod") {
1337a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actImeService = true;
1338a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.service.wallpaper.WallpaperService") {
1339a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actWallpaperService = true;
1340a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.accessibilityservice.AccessibilityService") {
1341a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actAccessibilityService = true;
1342a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            } else if (action == "android.printservice.PrintService") {
1343a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                actPrintService = true;
1344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1346a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (action == "android.intent.action.SEARCH") {
1347a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            isSearchable = true;
1348a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1349a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    }
1350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1351a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                    if (tag == "category") {
1352a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        String8 category = getAttribute(tree, NAME_ATTR, &error);
1353a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (error != "") {
1354a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            fprintf(stderr, "ERROR getting 'name' attribute: %s\n",
1355a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                    error.string());
1356a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            goto bail;
1357a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        }
1358a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                        if (withinActivity) {
1359a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                            if (category == "android.intent.category.LAUNCHER") {
1360a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                                isLauncherActivity = true;
1361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-1.6 implicitly granted permission compatibility logic
1368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 4) {
1369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteExternalStoragePermission) {
1370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
1371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \
1372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'targetSdkVersion < 4'\n");
1373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasWriteExternalStoragePermission = true;
1374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadPhoneStatePermission) {
1376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
1377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \
1378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'targetSdkVersion < 4'\n");
1379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If the application has requested WRITE_EXTERNAL_STORAGE, we will
1383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // force them to always take READ_EXTERNAL_STORAGE as well.  We always
1384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // do this (regardless of target API version) because we can't have
1385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // an app with write permission but not read permission.
1386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
1387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
1388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \
1389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested WRITE_EXTERNAL_STORAGE'\n");
1390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Pre-JellyBean call log permission compatibility.
1393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (targetSdk < 16) {
1394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasReadCallLogPermission && hasReadContactsPermission) {
1395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
1396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \
1397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'targetSdkVersion < 16 and requested READ_CONTACTS'\n");
1398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
1400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
1401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \
1402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n");
1403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /* The following blocks handle printing "inferred" uses-features, based
1407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * on whether related features or permissions are used by the app.
1408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * Note that the various spec*Feature variables denote whether the
1409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * relevant tag was *present* in the AndroidManfest, not that it was
1410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * present and set to true.
1411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             */
1412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Camera-related back-compatibility logic
1413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specCameraFeature) {
1414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (reqCameraFlashFeature) {
1415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // if app requested a sub-feature (autofocus or flash) and didn't
1416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // request the base camera feature, we infer that it meant to
1417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.camera'\n");
1418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.camera'," \
1419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'requested android.hardware.camera.flash feature'\n");
1420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (reqCameraAutofocusFeature) {
1421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // if app requested a sub-feature (autofocus or flash) and didn't
1422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // request the base camera feature, we infer that it meant to
1423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.camera'\n");
1424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.camera'," \
1425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'requested android.hardware.camera.autofocus feature'\n");
1426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (hasCameraPermission) {
1427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // if app wants to use camera but didn't request the feature, we infer
1428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // that it meant to, and further that it wants autofocus
1429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // (which was the 1.0 - 1.5 behavior)
1430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.camera'\n");
1431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!specCameraAutofocusFeature) {
1432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-feature:'android.hardware.camera.autofocus'\n");
1433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
1434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                "'requested android.permission.CAMERA permission'\n");
1435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Location-related back-compatibility logic
1440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specLocationFeature &&
1441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission ||
1442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) {
1443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app either takes a location-related permission or requests one of the
1444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // sub-features, we infer that it also meant to request the base location feature
1445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.location'\n");
1446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.location'," \
1447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested a location access permission'\n");
1448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specGpsFeature && hasGpsPermission) {
1450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes GPS (FINE location) perm but does not request the GPS
1451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.location.gps'\n");
1453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.location.gps'," \
1454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.ACCESS_FINE_LOCATION permission'\n");
1455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specNetworkLocFeature && hasCoarseLocPermission) {
1457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes Network location (COARSE location) perm but does not request the
1458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // network location feature, we infer that it meant to
1459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.location.network'\n");
1460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.location.network'," \
1461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.ACCESS_COARSE_LOCATION permission'\n");
1462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Bluetooth-related compatibility logic
1465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specBluetoothFeature && hasBluetoothPermission && (targetSdk > 4)) {
1466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes a Bluetooth permission but does not request the Bluetooth
1467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.bluetooth'\n");
1469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.bluetooth'," \
1470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
1471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "permission and targetSdkVersion > 4'\n");
1472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Microphone-related compatibility logic
1475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specMicrophoneFeature && hasRecordAudioPermission) {
1476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes the record-audio permission but does not request the microphone
1477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.microphone'\n");
1479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.microphone'," \
1480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.RECORD_AUDIO permission'\n");
1481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // WiFi-related compatibility logic
1484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specWiFiFeature && hasWiFiPermission) {
1485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes one of the WiFi permissions but does not request the WiFi
1486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // feature, we infer that it meant to
1487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.wifi'\n");
1488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.wifi'," \
1489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.permission.ACCESS_WIFI_STATE, " \
1490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "android.permission.CHANGE_WIFI_STATE, or " \
1491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n");
1492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Telephony-related compatibility logic
1495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) {
1496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes one of the telephony permissions or requests a sub-feature but
1497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // does not request the base telephony feature, we infer that it meant to
1498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.telephony'\n");
1499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.telephony'," \
1500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested a telephony-related permission or feature'\n");
1501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Touchscreen-related back-compatibility logic
1504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specTouchscreenFeature) { // not a typo!
1505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // all apps are presumed to require a touchscreen, unless they explicitly say
1506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
1507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Note that specTouchscreenFeature is true if the tag is present, regardless
1508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // of whether its value is true or false, so this is safe
1509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.touchscreen'\n");
1510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.touchscreen'," \
1511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'assumed you require a touch screen unless explicitly made optional'\n");
1512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
1514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // if app takes one of the telephony permissions or requests a sub-feature but
1515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // does not request the base telephony feature, we infer that it meant to
1516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
1517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
1518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "'requested android.hardware.touchscreen.multitouch.distinct feature'\n");
1519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Landscape/portrait-related compatibility logic
1522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!specScreenLandscapeFeature && !specScreenPortraitFeature) {
1523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // If the app has specified any activities in its manifest
1524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // that request a specific orientation, then assume that
1525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // orientation is required.
1526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (reqScreenLandscapeFeature) {
1527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.screen.landscape'\n");
1528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.screen.landscape'," \
1529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'one or more activities have specified a landscape orientation'\n");
1530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (reqScreenPortraitFeature) {
1532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-feature:'android.hardware.screen.portrait'\n");
1533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("uses-implied-feature:'android.hardware.screen.portrait'," \
1534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "'one or more activities have specified a portrait orientation'\n");
1535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasMainActivity) {
1539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("main\n");
1540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWidgetReceivers) {
1542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("app-widget\n");
1543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1544a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasDeviceAdminReceiver) {
1545a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                printf("device-admin\n");
1546a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasImeService) {
1548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("ime\n");
1549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasWallpaperService) {
1551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("wallpaper\n");
1552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1553a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasAccessibilityService) {
1554a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                printf("accessibility\n");
1555a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1556a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            if (hasPrintService) {
1557a5018c900f126ee8424c82497f32983873db741bAdam Lesinski                printf("print\n");
1558a5018c900f126ee8424c82497f32983873db741bAdam Lesinski            }
1559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherActivities) {
1560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-activities\n");
1561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (isSearchable) {
1563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("search\n");
1564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherReceivers) {
1566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-receivers\n");
1567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (hasOtherServices) {
1569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("other-services\n");
1570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For modern apps, if screen size buckets haven't been specified
1573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // but the new width ranges have, then infer the buckets from them.
1574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0 && normalScreen > 0 && largeScreen > 0 && xlargeScreen > 0
1575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    && requiresSmallestWidthDp > 0) {
1576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                int compatWidth = compatibleWidthLimitDp;
1577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (compatWidth <= 0) {
1578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    compatWidth = requiresSmallestWidthDp;
1579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 240 && compatWidth >= 240) {
1581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = -1;
1582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    smallScreen = 0;
1584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 320 && compatWidth >= 320) {
1586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = -1;
1587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    normalScreen = 0;
1589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 480 && compatWidth >= 480) {
1591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = -1;
1592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    largeScreen = 0;
1594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (requiresSmallestWidthDp <= 720 && compatWidth >= 720) {
1596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = -1;
1597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    xlargeScreen = 0;
1599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Determine default values for any unspecified screen sizes,
1603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // based on the target SDK of the package.  As of 4 (donut)
1604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the screen size support was introduced, so all default to
1605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // enabled.
1606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen > 0) {
1607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                smallScreen = targetSdk >= 4 ? -1 : 0;
1608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen > 0) {
1610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                normalScreen = -1;
1611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen > 0) {
1613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                largeScreen = targetSdk >= 4 ? -1 : 0;
1614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen > 0) {
1616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Introduced in Gingerbread.
1617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                xlargeScreen = targetSdk >= 9 ? -1 : 0;
1618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (anyDensity > 0) {
1620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                anyDensity = (targetSdk >= 4 || requiresSmallestWidthDp > 0
1621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        || compatibleWidthLimitDp > 0) ? -1 : 0;
1622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-screens:");
1624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (smallScreen != 0) {
1625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'small'");
1626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (normalScreen != 0) {
1628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'normal'");
1629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largeScreen != 0) {
1631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'large'");
1632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (xlargeScreen != 0) {
1634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" 'xlarge'");
1635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
1637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
1638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (requiresSmallestWidthDp > 0) {
1639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("requires-smallest-width:'%d'\n", requiresSmallestWidthDp);
1640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (compatibleWidthLimitDp > 0) {
1642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("compatible-width-limit:'%d'\n", compatibleWidthLimitDp);
1643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (largestWidthLimitDp > 0) {
1645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("largest-width-limit:'%d'\n", largestWidthLimitDp);
1646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("locales:");
1649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NL = locales.size();
1650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<NL; i++) {
1651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const char* localeStr =  locales[i].string();
1652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localeStr == NULL || strlen(localeStr) == 0) {
1653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    localeStr = "--_--";
1654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'", localeStr);
1656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
1658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("densities:");
1660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t ND = densities.size();
1661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<ND; i++) {
1662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%d'", densities[i]);
1663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("\n");
1665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
1667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (dir != NULL) {
1668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (dir->getFileCount() > 0) {
1669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("native-code:");
1670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t i=0; i<dir->getFileCount(); i++) {
1671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        printf(" '%s'", dir->getFileName(i).string());
1672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    printf("\n");
1674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                delete dir;
1676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("badger", option) == 0) {
1678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%s", CONSOLE_DATA);
1679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (strcmp("configurations", option) == 0) {
1680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<ResTable_config> configs;
1681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            res.getConfigurations(&configs);
1682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = configs.size();
1683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t i=0; i<N; i++) {
1684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("%s\n", configs[i].toString().string());
1685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
1687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
1688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
1693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
1695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (asset) {
1696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        delete asset;
1697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
1699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Handle the "add" command, which wants to add files to a new or
1704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * pre-existing archive.
1705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doAdd(Bundle* bundle)
1707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
1709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
1710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
1711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getUpdate()) {
1713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /* avoid confusion */
1714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: can't use '-u' with add\n");
1715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
1719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
1720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
1723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
1725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
1726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, true);
1730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
1731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening/creating '%s' as Zip file\n", zipFileName);
1732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
1736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
1737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
1739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s'... (from gzip)\n", fileName);
1740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
1741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
1742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bundle->getJunkPath()) {
1743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 storageName = String8(fileName).getPathLeaf();
1744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s' as '%s'...\n", fileName, storageName.string());
1745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, storageName.string(),
1746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bundle->getCompressionMethod(), NULL);
1747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf(" '%s'...\n", fileName);
1749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                result = zip->add(fileName, bundle->getCompressionMethod(), NULL);
1750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
1753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to add '%s' to '%s'", bundle->getFileSpecEntry(i), zipFileName);
1754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (result == NAME_NOT_FOUND) {
1755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": file not found\n");
1756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (result == ALREADY_EXISTS) {
1757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, ": already exists in archive\n");
1758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "\n");
1760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    result = NO_ERROR;
1766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
1768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
1769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
1770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Delete files from an existing archive.
1775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doRemove(Bundle* bundle)
1777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ZipFile* zip = NULL;
1779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = UNKNOWN_ERROR;
1780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* zipFileName;
1781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 1) {
1783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: must specify zip file name\n");
1784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zipFileName = bundle->getFileSpecEntry(0);
1787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getFileSpecCount() < 2) {
1789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "NOTE: nothing to do\n");
1790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip = openReadWrite(zipFileName, false);
1794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (zip == NULL) {
1795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: failed opening Zip archive '%s'\n",
1796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            zipFileName);
1797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (int i = 1; i < bundle->getFileSpecCount(); i++) {
1801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* fileName = bundle->getFileSpecEntry(i);
1802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ZipEntry* entry;
1803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        entry = zip->getEntryByName(fileName);
1805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (entry == NULL) {
1806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf(" '%s' NOT FOUND\n", fileName);
1807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
1808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = zip->remove(entry);
1811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != NO_ERROR) {
1813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "Unable to delete '%s' from '%s'\n",
1814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                bundle->getFileSpecEntry(i), zipFileName);
1815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* update the archive */
1820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    zip->flush();
1821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
1823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    delete zip;
1824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return (result != NO_ERROR);
1825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
1829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Package up an asset directory and associated application files.
1830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
1831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doPackage(Bundle* bundle)
1832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* outputAPKFile;
1834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int retVal = 1;
1835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
1836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptAssets> assets;
1837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int N;
1838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    FILE* fp;
1839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 dependencyFile;
1840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // -c zz_ZZ means do pseudolocalization
1842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResourceFilter filter;
1843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = filter.parse(bundle->getConfigurations());
1844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
1845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (filter.containsPseudo()) {
1848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bundle->setPseudolocalize(true);
1849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    N = bundle->getFileSpecCount();
1852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
1853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
1854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: no input files\n");
1855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outputAPKFile = bundle->getOutputAPKFile();
1859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Make sure the filenames provided exist and are of the appropriate type.
1861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
1862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        FileType type;
1863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        type = getFileType(outputAPKFile);
1864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (type != kFileTypeNonexistent && type != kFileTypeRegular) {
1865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr,
1866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "ERROR: output file '%s' exists but is not regular file\n",
1867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outputAPKFile);
1868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Load the assets.
1873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets = new AaptAssets();
1874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Set up the resource gathering in assets if we're going to generate
1876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // dependency files. Every time we encounter a resource while slurping
1877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the tree, we'll add it to these stores so we have full resource paths
1878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // to write to a dependency file.
1879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
1880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> resPathStore = new FilePathStore;
1881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullResPaths(resPathStore);
1882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<FilePathStore> assetPathStore = new FilePathStore;
1883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->setFullAssetPaths(assetPathStore);
1884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = assets->slurpFromArgs(bundle);
1887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
1888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getVerbose()) {
1892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assets->print(String8());
1893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If they asked for any fileAs that need to be compiled, do so.
1896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
1897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = buildResources(bundle, assets);
1898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != 0) {
1899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // At this point we've read everything and processed everything.  From here
1904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // on out it's just writing output files.
1905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
1906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Update symbols with information about which ones are needed as Java symbols.
1910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    assets->applyJavaSymbols();
1911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
1912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, do that here
1916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
1917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If this is the packaging step, generate the dependency file next to
1918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the output apk (e.g. bin/resources.ap_.d)
1919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outputAPKFile) {
1920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(outputAPKFile);
1921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Add the .d extension to the dependency file.
1922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.append(".d");
1923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
1924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Else if this is the R.java dependency generation step,
1925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // generate the dependency file in the R.java package subdirectory
1926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java.d
1927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile = String8(bundle->getRClassDir());
1928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            dependencyFile.appendPath("R.java.d");
1929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Make sure we have a clean dependency file to start with
1931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "w");
1932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
1933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out R.java constants
1936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!assets->havePrivateSymbols()) {
1937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getCustomPackage() == NULL) {
1938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Write the R.java file into the appropriate class directory
1939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // e.g. gen/com/foo/app/R.java
1940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, assets->getPackage(), true);
1941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
1942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String8 customPkg(bundle->getCustomPackage());
1943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = writeResourceSymbols(bundle, assets, customPkg, true);
1944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
1946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // If we have library files, we're going to write our R.java file into
1949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the appropriate class directory for those libraries as well.
1950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // e.g. gen/com/foo/app/lib/R.java
1951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundle->getExtraPackages() != NULL) {
1952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Split on colon
1953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 libs(bundle->getExtraPackages());
1954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* packageString = strtok(libs.lockBuffer(libs.length()), ":");
1955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (packageString != NULL) {
1956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Write the R.java file out with the correct package name
1957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = writeResourceSymbols(bundle, assets, String8(packageString), true);
1958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < 0) {
1959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
1960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                packageString = strtok(NULL, ":");
1962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            libs.unlockBuffer();
1964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
1966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getPackage(), false);
1967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
1968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeResourceSymbols(bundle, assets, assets->getSymbolsPrivatePackage(), true);
1971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err < 0) {
1972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write out the ProGuard file
1977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = writeProguardFile(bundle, assets);
1978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < 0) {
1979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
1980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Write the apk
1983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outputAPKFile) {
1984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeAPK(bundle, assets, String8(outputAPKFile));
1985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
1986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile);
1987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
1988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If we've been asked to generate a dependency file, we need to finish up here.
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the writeResourceSymbols and writeAPK functions have already written the target
1993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // half of the dependency file, now we need to write the prerequisites. (files that
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // the R.java file or .ap_ file depend on)
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getGenDependencies()) {
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now that writeResourceSymbols or writeAPK has taken care of writing
1997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the targets to our dependency file, we'll write the prereqs
1998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fp = fopen(dependencyFile, "a+");
1999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, " : ");
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool includeRaw = (outputAPKFile != NULL);
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = writeDependencyPreReqs(bundle, assets, fp, includeRaw);
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Also manually add the AndroidManifeset since it's not under res/ or assets/
2003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // and therefore was not added to our pathstores during slurping
2004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(fp, "%s \\\n", bundle->getAndroidManifestFile());
2005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fclose(fp);
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    retVal = 0;
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (SourcePos::hasErrors()) {
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos::printErrors(stderr);
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return retVal;
2014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * PRECONDITIONS
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -S flag points to a source directory containing drawable* folders
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -C flag points to destination directory. The folder structure in the
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *     source directory will be mirrored to the destination (cache) directory
2022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * POSTCONDITIONS
2024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  Destination directory will be updated to match the PNG files in
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  the source directory.
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doCrunch(Bundle* bundle)
2028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching PNG Files in ");
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "source dir: %s\n", bundle->getResourceSourceDirs()[0]);
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "To destination dir: %s\n", bundle->getCrunchedOutputDir());
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    updatePreProcessedCache(bundle);
2034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Do PNG Crunching on a single flag
2040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -i points to a single png file
2041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *  -o points to a single png output file
2042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint doSingleCrunch(Bundle* bundle)
2044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "Crunching single PNG file: %s\n", bundle->getSingleCrunchInputFile());
2046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stdout, "\tOutput file: %s\n", bundle->getSingleCrunchOutputFile());
2047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 input(bundle->getSingleCrunchInputFile());
2049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String8 output(bundle->getSingleCrunchOutputFile());
2050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (preProcessImageToCache(bundle, input, output) != NO_ERROR) {
2052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // we can't return the status_t as it gets truncate to the lower 8 bits.
2053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 42;
2054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskichar CONSOLE_DATA[2925] = {
2060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63,
2065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    86, 35, 40, 46, 46, 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83,
2066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    62, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 46, 58, 59, 61, 59, 61, 81,
2069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 66, 96, 61, 61, 58, 46, 46, 46, 58, 32, 32, 32, 32, 32, 32,
2070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, 81, 81, 102, 59, 61, 59,
2073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59,
2076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, 46, 32,
2077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87,
2080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32,
2081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    47, 61, 59, 59, 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58,
2084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    121, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81,
2087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 109, 58, 59, 59, 59, 59, 61, 109, 81, 81, 76, 46, 32, 32, 32,
2088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, 81, 81, 81, 81, 59, 61, 59,
2091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 60, 81, 91, 59,
2094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, 81, 76, 32,
2095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
2098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32,
2099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 93, 40, 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81,
2102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 46, 46, 32, 46, 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109,
2105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 87, 46, 58, 61, 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32,
2106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 46, 61, 59, 61, 61, 61, 59, 61, 61, 59,
2108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 58, 46, 46, 41, 58, 59, 58, 81, 81, 81, 81, 69, 58, 59, 59,
2109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 58, 59,
2111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61, 46,
2112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, 96, 32, 32, 32,
2113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, 81,
2116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
2117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81,
2118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    67, 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58,
2120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32,
2121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59,
2122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37,
2123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    73, 108, 108, 62, 52, 81, 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59,
2124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 61, 59, 61, 61, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 45, 57, 101, 43, 43, 61, 61, 59, 59, 59, 59, 59, 59, 61, 59, 59,
2126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 97, 46, 61, 108, 62, 126, 58, 106, 80, 96,
2127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 61,
2128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 45, 46, 32,
2129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 58, 59, 59, 59, 59, 61,
2130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, 58, 59, 59, 59,
2131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, 99, 32, 32,
2132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
2134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
2135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10,
2136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 61, 58, 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81,
2138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 58, 59, 59, 59, 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41,
2139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    87, 66, 33, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81,
2141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58,
2142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    45, 32, 46, 32, 32, 32, 32, 32, 46, 32, 126, 96, 32, 32, 32, 32, 32, 32,
2143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32,
2146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58,
2148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58,
2149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
2152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32,
2153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 40, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
2158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106,
2159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59,
2160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 61, 58, 58, 81, 81, 81, 81, 81, 81, 81, 81,
2163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32,
2164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
2165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 59,
2167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, 81,
2170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
2171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81,
2174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    81, 102, 94, 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
2176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59,
2177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 43, 63, 36, 81, 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59,
2178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 43, 33,
2181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    58, 126, 126, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32,
2182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
2183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46,
2184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, 59, 59, 59, 59, 59,
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32,
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
2187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 58, 95,
2188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, 59,
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45,
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32,
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59,
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59,
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 59, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 45, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 58, 32,
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 61,
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59,
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, 59, 59,
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32,
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32,
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61,
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59,
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    59, 59, 59, 58, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32,
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 61, 59, 58, 45, 45, 32, 32, 32,
2218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski  };
2224