1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Copyright 2006 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski// Build resource files from raw assets.
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceTable.h"
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
9de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski#include "AaptUtil.h"
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "XMLNode.h"
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceFilter.h"
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include "ResourceIdCache.h"
13dcdfe9fef4b07ee53d312c3fbecc74cb215ace6fAdam Lesinski#include "SdkConstants.h"
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
159b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski#include <algorithm>
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <androidfw/ResourceTypes.h>
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/ByteOrder.h>
1882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski#include <utils/TypeHelpers.h>
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <stdarg.h>
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
212412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe// SSIZE: mingw does not have signed size_t == ssize_t.
222412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
23b12f2410c7bdbf90bd8a77b897846ee2763e3037Elliott Hughes#if !defined(_WIN32)
242412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#  define SSIZE(x) x
252412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#  define STATUST(x) x
262412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#else
272412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#  define SSIZE(x) (signed size_t)x
282412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#  define STATUST(x) (status_t)x
292412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#endif
302412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe
312412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe// Set to true for noisy debug output.
322412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampestatic const bool kIsDebug = false;
332412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe
342412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#if PRINT_STRING_METRICS
352412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampestatic const bool kPrintStringMetrics = true;
362412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#else
372412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampestatic const bool kPrintStringMetrics = false;
382412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe#endif
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
409b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinskistatic const char* kAttrPrivateType = "^attr-private";
419b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinskistatus_t compileXmlFile(const Bundle* bundle,
43e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                        const sp<AaptAssets>& assets,
44e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                        const String16& resourceName,
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<AaptFile>& target,
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResourceTable* table,
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int options)
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<XMLNode> root = XMLNode::parse(target);
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (root == NULL) {
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
53a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin
54e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    return compileXmlFile(bundle, assets, resourceName, root, target, table, options);
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
57e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinskistatus_t compileXmlFile(const Bundle* bundle,
58e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                        const sp<AaptAssets>& assets,
59e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                        const String16& resourceName,
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<AaptFile>& target,
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<AaptFile>& outTarget,
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResourceTable* table,
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int options)
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<XMLNode> root = XMLNode::parse(target);
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (root == NULL) {
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
70e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    return compileXmlFile(bundle, assets, resourceName, root, outTarget, table, options);
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
73e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinskistatus_t compileXmlFile(const Bundle* bundle,
74e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                        const sp<AaptAssets>& assets,
75e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                        const String16& resourceName,
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<XMLNode>& root,
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<AaptFile>& target,
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResourceTable* table,
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int options)
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
81cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    if (table->versionForCompat(bundle, resourceName, target, root)) {
82cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        // The file was versioned, so stop processing here.
83cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        // The resource entry has already been removed and the new one added.
84cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        // Remove the assets entry.
85cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        sp<AaptDir> resDir = assets->getDirs().valueFor(String8("res"));
86cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        sp<AaptDir> dir = resDir->getDirs().valueFor(target->getGroupEntry().toDirName(
87cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski                target->getResourceType()));
88cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        dir->removeFile(target->getPath().getPathLeaf());
89cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        return NO_ERROR;
90cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    }
91cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        root->removeWhitespace(true, NULL);
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else  if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        root->removeWhitespace(false, NULL);
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((options&XML_COMPILE_UTF8) != 0) {
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        root->setUTF8(true);
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
10207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    if (table->processBundleFormat(bundle, resourceName, target, root) != NO_ERROR) {
10307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        return UNKNOWN_ERROR;
10407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    }
1055b9847ca3fbcd0bb2528dd2b4c0b789e2d501684Adam Lesinski
10607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    bool hasErrors = false;
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((options&XML_COMPILE_ASSIGN_ATTRIBUTE_IDS) != 0) {
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = root->assignResourceIds(assets, table);
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            hasErrors = true;
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
11407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    if ((options&XML_COMPILE_PARSE_VALUES) != 0) {
11507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        status_t err = root->parseValues(assets, table);
11607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (err != NO_ERROR) {
11707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            hasErrors = true;
11807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (hasErrors) {
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
124e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
125e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    if (table->modifyForCompat(bundle, resourceName, target, root) != NO_ERROR) {
126e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        return UNKNOWN_ERROR;
127e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
12887332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe
1292412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
1302412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Input XML Resource:\n");
1312412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        root->print();
1322412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
13307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    status_t err = root->flatten(target,
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (options&XML_COMPILE_STRIP_COMMENTS) != 0,
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (options&XML_COMPILE_STRIP_RAW_VALUES) != 0);
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1402412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
1412412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Output XML Resource:\n");
1422412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        ResXMLTree tree;
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        tree.setTo(target->getData(), target->getSize());
1442412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printXMLBlock(&tree);
1452412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    target->setCompressionMethod(ZipEntry::kCompressDeflated);
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistruct flag_entry
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* name;
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t nameLen;
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t value;
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char* description;
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t referenceArray[] =
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'r', 'e', 'f', 'e', 'r', 'e', 'n', 'c', 'e' };
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t stringArray[] =
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 's', 't', 'r', 'i', 'n', 'g' };
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t integerArray[] =
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'i', 'n', 't', 'e', 'g', 'e', 'r' };
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t booleanArray[] =
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'b', 'o', 'o', 'l', 'e', 'a', 'n' };
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t colorArray[] =
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'c', 'o', 'l', 'o', 'r' };
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t floatArray[] =
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'f', 'l', 'o', 'a', 't' };
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t dimensionArray[] =
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n' };
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t fractionArray[] =
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'f', 'r', 'a', 'c', 't', 'i', 'o', 'n' };
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t enumArray[] =
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'e', 'n', 'u', 'm' };
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t flagsArray[] =
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { 'f', 'l', 'a', 'g', 's' };
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const flag_entry gFormatFlags[] = {
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { referenceArray, sizeof(referenceArray)/2, ResTable_map::TYPE_REFERENCE,
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a reference to another resource, in the form \"<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>\"\n"
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "or to a theme attribute in the form \"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\"."},
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { stringArray, sizeof(stringArray)/2, ResTable_map::TYPE_STRING,
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a string value, using '\\\\;' to escape characters such as '\\\\n' or '\\\\uxxxx' for a unicode character." },
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { integerArray, sizeof(integerArray)/2, ResTable_map::TYPE_INTEGER,
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "an integer value, such as \"<code>100</code>\"." },
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { booleanArray, sizeof(booleanArray)/2, ResTable_map::TYPE_BOOLEAN,
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a boolean value, either \"<code>true</code>\" or \"<code>false</code>\"." },
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { colorArray, sizeof(colorArray)/2, ResTable_map::TYPE_COLOR,
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a color value, in the form of \"<code>#<i>rgb</i></code>\", \"<code>#<i>argb</i></code>\",\n"
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "\"<code>#<i>rrggbb</i></code>\", or \"<code>#<i>aarrggbb</i></code>\"." },
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { floatArray, sizeof(floatArray)/2, ResTable_map::TYPE_FLOAT,
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a floating point value, such as \"<code>1.2</code>\"."},
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { dimensionArray, sizeof(dimensionArray)/2, ResTable_map::TYPE_DIMENSION,
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a dimension value, which is a floating point number appended with a unit such as \"<code>14.5sp</code>\".\n"
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\n"
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "in (inches), mm (millimeters)." },
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { fractionArray, sizeof(fractionArray)/2, ResTable_map::TYPE_FRACTION,
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "a fractional value, which is a floating point number appended with either % or %p, such as \"<code>14.5%</code>\".\n"
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to\n"
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      "some parent container." },
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { enumArray, sizeof(enumArray)/2, ResTable_map::TYPE_ENUM, NULL },
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { flagsArray, sizeof(flagsArray)/2, ResTable_map::TYPE_FLAGS, NULL },
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { NULL, 0, 0, NULL }
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t suggestedArray[] = { 's', 'u', 'g', 'g', 'e', 's', 't', 'e', 'd' };
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const flag_entry l10nRequiredFlags[] = {
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { suggestedArray, sizeof(suggestedArray)/2, ResTable_map::L10N_SUGGESTED, NULL },
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    { NULL, 0, 0, NULL }
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char16_t nulStr[] = { 0 };
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic uint32_t parse_flags(const char16_t* str, size_t len,
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             const flag_entry* flags, bool* outError = NULL)
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (len > 0 && isspace(*str)) {
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        str++;
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        len--;
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (len > 0 && isspace(str[len-1])) {
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        len--;
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* const end = str + len;
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t value = 0;
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (str < end) {
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char16_t* div = str;
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (div < end && *div != '|') {
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            div++;
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const flag_entry* cur = flags;
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (cur->name) {
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strzcmp16(cur->name, cur->nameLen, str, div-str) == 0) {
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                value |= cur->value;
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            cur++;
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!cur->name) {
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (outError) *outError = true;
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return 0;
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        str = div < end ? div+1 : div;
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outError) *outError = false;
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return value;
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic String16 mayOrMust(int type, int flags)
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((type&(~flags)) == 0) {
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return String16("<p>Must");
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return String16("<p>May");
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic void appendTypeInfo(ResourceTable* outTable, const String16& pkg,
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16& typeName, const String16& ident, int type,
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const flag_entry* flags)
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool hadType = false;
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (flags->name) {
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if ((type&flags->value) != 0 && flags->description != NULL) {
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 fullMsg(mayOrMust(type, flags->value));
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fullMsg.append(String16(" be "));
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fullMsg.append(String16(flags->description));
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            outTable->appendTypeComment(pkg, typeName, ident, fullMsg);
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            hadType = true;
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flags++;
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (hadType && (type&ResTable_map::TYPE_REFERENCE) == 0) {
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outTable->appendTypeComment(pkg, typeName, ident,
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16("<p>This may also be a reference to a resource (in the form\n"
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         "\"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>\") or\n"
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         "theme attribute (in the form\n"
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         "\"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\")\n"
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                         "containing a value of this type."));
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistruct PendingAttribute
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 myPackage;
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const SourcePos sourcePos;
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const bool appendComment;
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int32_t type;
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 ident;
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 comment;
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool hasErrors;
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool added;
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PendingAttribute(String16 _package, const sp<AaptFile>& in,
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResXMLTree& block, bool _appendComment)
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        : myPackage(_package)
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        , sourcePos(in->getPrintableSource(), block.getLineNumber())
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        , appendComment(_appendComment)
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        , type(ResTable_map::TYPE_ANY)
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        , hasErrors(false)
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        , added(false)
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t createIfNeeded(ResourceTable* outTable)
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (added || hasErrors) {
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_ERROR;
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        added = true;
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
322afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        if (!outTable->makeAttribute(myPackage, ident, sourcePos, type, comment, appendComment)) {
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            hasErrors = true;
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
326afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        return NO_ERROR;
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic status_t compileAttribute(const sp<AaptFile>& in,
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 ResXMLTree& block,
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& myPackage,
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 ResourceTable* outTable,
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 String16* outIdent = NULL,
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 bool inStyleable = false)
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PendingAttribute attr(myPackage, in, block, inStyleable);
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 attr16("attr");
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 id16("id");
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Attribute type constants.
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 enum16("enum");
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 flag16("flag");
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t identIdx = block.indexOfAttribute(NULL, "name");
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (identIdx >= 0) {
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.ident = String16(block.getAttributeStringValue(identIdx, &len));
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outIdent) {
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outIdent = attr.ident;
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.sourcePos.error("A 'name' attribute is required for <attr>\n");
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.hasErrors = true;
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    attr.comment = String16(
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            block.getComment(&len) ? block.getComment(&len) : nulStr);
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t typeIdx = block.indexOfAttribute(NULL, "format");
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (typeIdx >= 0) {
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String16 typeStr = String16(block.getAttributeStringValue(typeIdx, &len));
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.type = parse_flags(typeStr.string(), typeStr.size(), gFormatFlags);
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (attr.type == 0) {
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.sourcePos.error("Tag <attr> 'format' attribute value \"%s\" not valid\n",
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(typeStr).string());
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.hasErrors = true;
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.createIfNeeded(outTable);
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (!inStyleable) {
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Attribute definitions outside of styleables always define the
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // attribute as a generic value.
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.createIfNeeded(outTable);
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).string(), attr.type);
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t minIdx = block.indexOfAttribute(NULL, "min");
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (minIdx >= 0) {
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String16 val = String16(block.getAttributeStringValue(minIdx, &len));
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!ResTable::stringToInt(val.string(), val.size(), NULL)) {
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.sourcePos.error("Tag <attr> 'min' attribute must be a number, not \"%s\"\n",
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(val).string());
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.hasErrors = true;
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.createIfNeeded(outTable);
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!attr.hasErrors) {
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16(""), String16("^min"), String16(val), NULL, NULL);
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (err != NO_ERROR) {
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.hasErrors = true;
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t maxIdx = block.indexOfAttribute(NULL, "max");
401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (maxIdx >= 0) {
402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String16 val = String16(block.getAttributeStringValue(maxIdx, &len));
403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!ResTable::stringToInt(val.string(), val.size(), NULL)) {
404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.sourcePos.error("Tag <attr> 'max' attribute must be a number, not \"%s\"\n",
405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(val).string());
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.hasErrors = true;
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.createIfNeeded(outTable);
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!attr.hasErrors) {
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16(""), String16("^max"), String16(val), NULL, NULL);
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.hasErrors = true;
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((minIdx >= 0 || maxIdx >= 0) && (attr.type&ResTable_map::TYPE_INTEGER) == 0) {
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.sourcePos.error("Tag <attr> must have format=integer attribute if using max or min\n");
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.hasErrors = true;
419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t l10nIdx = block.indexOfAttribute(NULL, "localization");
422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (l10nIdx >= 0) {
423f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert        const char16_t* str = block.getAttributeStringValue(l10nIdx, &len);
424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool error;
425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error);
426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (error) {
427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.sourcePos.error("Tag <attr> 'localization' attribute value \"%s\" not valid\n",
428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(str).string());
429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.hasErrors = true;
430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        attr.createIfNeeded(outTable);
432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!attr.hasErrors) {
433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char buf[11];
434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sprintf(buf, "%d", l10n_required);
435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16(""), String16("^l10n"), String16(buf), NULL, NULL);
437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (err != NO_ERROR) {
438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.hasErrors = true;
439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 enumOrFlagsComment;
444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::START_TAG) {
447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            uint32_t localType = 0;
448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strcmp16(block.getElementName(&len), enum16.string()) == 0) {
449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localType = ResTable_map::TYPE_ENUM;
450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), flag16.string()) == 0) {
451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                localType = ResTable_map::TYPE_FLAGS;
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber())
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        .error("Tag <%s> can not appear inside <attr>, only <enum> or <flag>\n",
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(block.getElementName(&len)).string());
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            attr.createIfNeeded(outTable);
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (attr.type == ResTable_map::TYPE_ANY) {
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // No type was explicitly stated, so supplying enum tags
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // implicitly creates an enum or flag.
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.type = 0;
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if ((attr.type&(ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)) == 0) {
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Wasn't originally specified as an enum, so update its type.
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.type |= localType;
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!attr.hasErrors) {
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    char numberStr[16];
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sprintf(numberStr, "%d", attr.type);
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            myPackage, attr16, attr.ident, String16(""),
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String16("^type"), String16(numberStr), NULL, NULL, true);
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err != NO_ERROR) {
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        attr.hasErrors = true;
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if ((uint32_t)(attr.type&(ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)) != localType) {
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (localType == ResTable_map::TYPE_ENUM) {
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber())
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            .error("<enum> attribute can not be used inside a flags format\n");
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    attr.hasErrors = true;
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber())
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            .error("<flag> attribute can not be used inside a enum format\n");
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    attr.hasErrors = true;
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 itemIdent;
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "name");
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (itemIdentIdx >= 0) {
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                itemIdent = String16(block.getAttributeStringValue(itemIdentIdx, &len));
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber())
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        .error("A 'name' attribute is required for <enum> or <flag>\n");
499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.hasErrors = true;
500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 value;
503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ssize_t valueIdx = block.indexOfAttribute(NULL, "value");
504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (valueIdx >= 0) {
505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                value = String16(block.getAttributeStringValue(valueIdx, &len));
506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber())
508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        .error("A 'value' attribute is required for <enum> or <flag>\n");
509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.hasErrors = true;
510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!attr.hasErrors && !ResTable::stringToInt(value.string(), value.size(), NULL)) {
512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber())
513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        .error("Tag <enum> or <flag> 'value' attribute must be a number,"
514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        " not \"%s\"\n",
515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(value).string());
516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                attr.hasErrors = true;
517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!attr.hasErrors) {
520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (enumOrFlagsComment.size() == 0) {
521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    enumOrFlagsComment.append(mayOrMust(attr.type,
522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS));
523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    enumOrFlagsComment.append((attr.type&ResTable_map::TYPE_ENUM)
524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       ? String16(" be one of the following constant values.")
525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       : String16(" be one or more (separated by '|') of the following constant values."));
526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    enumOrFlagsComment.append(String16("</p>\n<table>\n"
527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                "<colgroup align=\"left\" />\n"
528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                "<colgroup align=\"left\" />\n"
529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                "<colgroup align=\"left\" />\n"
530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>"));
531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                enumOrFlagsComment.append(String16("\n<tr><td><code>"));
534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                enumOrFlagsComment.append(itemIdent);
535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                enumOrFlagsComment.append(String16("</code></td><td>"));
536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                enumOrFlagsComment.append(value);
537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                enumOrFlagsComment.append(String16("</td><td>"));
538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (block.getComment(&len)) {
539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    enumOrFlagsComment.append(String16(block.getComment(&len)));
540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                enumOrFlagsComment.append(String16("</td></tr>"));
542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       myPackage,
545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       attr16, attr.ident, String16(""),
546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       itemIdent, value, NULL, NULL, false, true);
547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err != NO_ERROR) {
548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    attr.hasErrors = true;
549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (code == ResXMLTree::END_TAG) {
552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strcmp16(block.getElementName(&len), attr16.string()) == 0) {
553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if ((attr.type&ResTable_map::TYPE_ENUM) != 0) {
556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (strcmp16(block.getElementName(&len), enum16.string()) != 0) {
557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber())
558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            .error("Found tag </%s> where </enum> is expected\n",
559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8(block.getElementName(&len)).string());
560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return UNKNOWN_ERROR;
561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (strcmp16(block.getElementName(&len), flag16.string()) != 0) {
564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber())
565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            .error("Found tag </%s> where </flag> is expected\n",
566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8(block.getElementName(&len)).string());
567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return UNKNOWN_ERROR;
568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!attr.hasErrors && attr.added) {
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        appendTypeInfo(outTable, myPackage, attr16, attr.ident, attr.type, gFormatFlags);
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!attr.hasErrors && enumOrFlagsComment.size() > 0) {
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        enumOrFlagsComment.append(String16("\n</table>"));
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outTable->appendTypeComment(myPackage, attr16, attr.ident, enumOrFlagsComment);
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool localeIsDefined(const ResTable_config& config)
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return config.locale == 0;
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t parseAndAddBag(Bundle* bundle,
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<AaptFile>& in,
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResXMLTree* block,
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const ResTable_config& config,
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& myPackage,
596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& curType,
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& ident,
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& parentIdent,
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& itemIdent,
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t curFormat,
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        bool isFormatted,
6022412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        const String16& /* product */,
603a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        PseudolocalizationMethod pseudolocalize,
604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const bool overwrite,
605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResourceTable* outTable)
606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 item16("item");
609a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 str;
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<StringPool::entry_style_span> spans;
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = parseStyledString(bundle, in->getPrintableSource().string(),
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            block, item16, &str, &spans, isFormatted,
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            pseudolocalize);
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
6182412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe
6192412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
6202412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d "
6212412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                " pid=%s, bag=%s, id=%s: %s\n",
6222412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                config.language[0], config.language[1],
6232412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                config.country[0], config.country[1],
6242412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                config.orientation, config.density,
6252412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(parentIdent).string(),
6262412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(ident).string(),
6272412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(itemIdent).string(),
6282412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(str).string());
6292412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           myPackage, curType, ident, parentIdent, itemIdent, str,
633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           &spans, &config, overwrite, false, curFormat);
634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Returns true if needle is one of the elements in the comma-separated list
639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * haystack, false otherwise.
640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool isInProductList(const String16& needle, const String16& haystack) {
642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t *needle2 = needle.string();
643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t *haystack2 = haystack.string();
644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t needlesize = needle.size();
645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (*haystack2 != '\0') {
647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (strncmp16(haystack2, needle2, needlesize) == 0) {
648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') {
649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return true;
650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (*haystack2 != '\0' && *haystack2 != ',') {
654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            haystack2++;
655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (*haystack2 == ',') {
657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            haystack2++;
658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
6648ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski/*
6658ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski * A simple container that holds a resource type and name. It is ordered first by type then
6668ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski * by name.
6678ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski */
6688ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinskistruct type_ident_pair_t {
6698ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    String16 type;
6708ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    String16 ident;
6718ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski
6728ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    type_ident_pair_t() { };
6738ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    type_ident_pair_t(const String16& t, const String16& i) : type(t), ident(i) { }
6748ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    type_ident_pair_t(const type_ident_pair_t& o) : type(o.type), ident(o.ident) { }
6758ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    inline bool operator < (const type_ident_pair_t& o) const {
6768ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        int cmp = compare_type(type, o.type);
6778ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        if (cmp < 0) {
6788ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski            return true;
6798ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        } else if (cmp > 0) {
6808ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski            return false;
6818ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        } else {
6828ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski            return strictly_order_type(ident, o.ident);
6838ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        }
6848ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    }
6858ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski};
6868ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski
6878ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski
688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t parseAndAddEntry(Bundle* bundle,
689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const sp<AaptFile>& in,
690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResXMLTree* block,
691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const ResTable_config& config,
692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& myPackage,
693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& curType,
694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& ident,
695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& curTag,
696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        bool curIsStyled,
697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        int32_t curFormat,
698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        bool isFormatted,
699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const String16& product,
700a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        PseudolocalizationMethod pseudolocalize,
701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const bool overwrite,
7028ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        KeyedVector<type_ident_pair_t, bool>* skippedResourceNames,
703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResourceTable* outTable)
704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err;
706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 str;
708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<StringPool::entry_style_span> spans;
709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = parseStyledString(bundle, in->getPrintableSource().string(), block,
710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            curTag, &str, curIsStyled ? &spans : NULL,
711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            isFormatted, pseudolocalize);
712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err < NO_ERROR) {
714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /*
718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * If a product type was specified on the command line
719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * and also in the string, and the two are not the same,
720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * return without adding the string.
721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char *bundleProduct = bundle->getProduct();
724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundleProduct == NULL) {
725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bundleProduct = "";
726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (product.size() != 0) {
729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /*
730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * If the command-line-specified product is empty, only "default"
731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * matches.  Other variants are skipped.  This is so generation
732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         * of the R.java file when the product is not known is predictable.
733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski         */
734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (bundleProduct[0] == '\0') {
736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strcmp16(String16("default").string(), product.string()) != 0) {
7378ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                /*
7388ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                 * This string has a product other than 'default'. Do not add it,
7398ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                 * but record it so that if we do not see the same string with
7408ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                 * product 'default' or no product, then report an error.
7418ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                 */
7428ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                skippedResourceNames->replaceValueFor(
7438ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        type_ident_pair_t(curType, ident), true);
744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return NO_ERROR;
745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            /*
748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * The command-line product is not empty.
749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * If the product for this string is on the command-line list,
750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * it matches.  "default" also matches, but only if nothing
751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             * else has matched already.
752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski             */
753282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (isInProductList(product, String16(bundleProduct))) {
755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ;
756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(String16("default").string(), product.string()) == 0 &&
757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       !outTable->hasBagOrEntry(myPackage, curType, ident, config)) {
758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ;
759282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return NO_ERROR;
761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
763282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
764282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
7652412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
7662412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
7672412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                config.language[0], config.language[1],
7682412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                config.country[0], config.country[1],
7692412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                config.orientation, config.density,
7702412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(ident).string(), String8(str).string());
7712412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             myPackage, curType, ident, str, &spans, &config,
775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             false, curFormat, overwrite);
776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t compileResourceFile(Bundle* bundle,
781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             const sp<AaptAssets>& assets,
782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             const sp<AaptFile>& in,
783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             const ResTable_config& defParams,
784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             const bool overwrite,
785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                             ResourceTable* outTable)
786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree block;
788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = parseXMLResource(in, &block, false, true);
789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Top-level tag.
794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 resources16("resources");
795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Identifier declaration tags.
797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 declare_styleable16("declare-styleable");
798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 attr16("attr");
799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Data creation organizational tags.
801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 string16("string");
802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 drawable16("drawable");
803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 color16("color");
804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 bool16("bool");
805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 integer16("integer");
806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 dimen16("dimen");
807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 fraction16("fraction");
808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 style16("style");
809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 plurals16("plurals");
810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 array16("array");
811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 string_array16("string-array");
812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 integer_array16("integer-array");
813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 public16("public");
814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 public_padding16("public-padding");
815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 private_symbols16("private-symbols");
816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 java_symbol16("java-symbol");
817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 add_resource16("add-resource");
818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 skip16("skip");
819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 eat_comment16("eat-comment");
820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Data creation tags.
822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 bag16("bag");
823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 item16("item");
824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Attribute type constants.
826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 enum16("enum");
827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // plural values
829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 other16("other");
830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 quantityOther16("^other");
831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 zero16("zero");
832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 quantityZero16("^zero");
833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 one16("one");
834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 quantityOne16("^one");
835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 two16("two");
836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 quantityTwo16("^two");
837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 few16("few");
838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 quantityFew16("^few");
839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 many16("many");
840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 quantityMany16("^many");
841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // useful attribute names and special values
843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 name16("name");
844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 translatable16("translatable");
845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 formatted16("formatted");
846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 false16("false");
847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 myPackage(assets->getPackage());
849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool hasErrors = false;
851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool fileIsTranslatable = true;
853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) {
854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fileIsTranslatable = false;
855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
8598ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // Stores the resource names that were skipped. Typically this happens when
8608ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // AAPT is invoked without a product specified and a resource has no
8618ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // 'default' product attribute.
8628ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    KeyedVector<type_ident_pair_t, bool> skippedResourceNames;
8638ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski
864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResXMLTree::event_code_t code;
865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    do {
866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        code = block.next();
867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } while (code == ResXMLTree::START_NAMESPACE);
868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t len;
870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (code != ResXMLTree::START_TAG) {
871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "No start tag found\n");
873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strcmp16(block.getElementName(&len), resources16.string()) != 0) {
876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                "Invalid start tag %s\n", String8(block.getElementName(&len)).string());
878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config curParams(defParams);
882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_config pseudoParams(curParams);
884a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoParams.language[0] = 'e';
885a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoParams.language[1] = 'n';
886a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoParams.country[0] = 'X';
887a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoParams.country[1] = 'A';
888a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin
889a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin    ResTable_config pseudoBidiParams(curParams);
890a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoBidiParams.language[0] = 'a';
891a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoBidiParams.language[1] = 'r';
892a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoBidiParams.country[0] = 'X';
893a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin        pseudoBidiParams.country[1] = 'B';
894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
89547843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk    // We should skip resources for pseudolocales if they were
89647843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk    // already added automatically. This is a fix for a transition period when
89747843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk    // manually pseudolocalized resources may be expected.
89847843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk    // TODO: remove this check after next SDK version release.
89947843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk    if ((bundle->getPseudolocalize() & PSEUDO_ACCENTED &&
90047843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk         curParams.locale == pseudoParams.locale) ||
90147843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk        (bundle->getPseudolocalize() & PSEUDO_BIDI &&
90247843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk         curParams.locale == pseudoBidiParams.locale)) {
90347843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk        SourcePos(in->getPrintableSource(), 0).warning(
90447843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk                "Resource file %s is skipped as pseudolocalization"
90547843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk                " was done automatically.",
90647843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk                in->getPrintableSource().string());
90747843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk        return NO_ERROR;
90847843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk    }
90947843df11fe88b30abcac324173b6c15f16cc797Igor Viarheichyk
910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (code == ResXMLTree::START_TAG) {
912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String16* curTag = NULL;
913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 curType;
9145892248580859620db90d5ef2e3c2f48531933faAdrian Roos            String16 curName;
915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int32_t curFormat = ResTable_map::TYPE_ANY;
916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool curIsBag = false;
917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool curIsBagReplaceOnOverwrite = false;
918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool curIsStyled = false;
919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool curIsPseudolocalizable = false;
920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool curIsFormatted = fileIsTranslatable;
921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool localHasErrors = false;
922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT
925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        && code != ResXMLTree::BAD_DOCUMENT) {
926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT
936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        && code != ResXMLTree::BAD_DOCUMENT) {
937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), public16.string()) == 0) {
946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 type;
949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (typeIdx < 0) {
951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'type' attribute is required for <public>\n");
952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                type = String16(block.getAttributeStringValue(typeIdx, &len));
955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 name;
957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (nameIdx < 0) {
959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'name' attribute is required for <public>\n");
960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                name = String16(block.getAttributeStringValue(nameIdx, &len));
963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                uint32_t ident = 0;
965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t identIdx = block.indexOfAttribute(NULL, "id");
966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (identIdx >= 0) {
967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    const char16_t* identStr = block.getAttributeStringValue(identIdx, &len);
968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Res_value identValue;
969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!ResTable::stringToInt(identStr, len, &identValue)) {
970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        srcPos.error("Given 'id' attribute is not an integer: %s\n",
971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String8(block.getAttributeStringValue(identIdx, &len)).string());
972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ident = identValue.data;
975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        nextPublicId.replaceValueFor(type, ident+1);
976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (nextPublicId.indexOfKey(type) < 0) {
978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("No 'id' attribute supplied <public>,"
979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            " and no previous id defined in this file.\n");
980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (!localHasErrors) {
982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ident = nextPublicId.valueFor(type);
983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    nextPublicId.replaceValueFor(type, ident+1);
984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!localHasErrors) {
987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    err = outTable->addPublic(srcPos, myPackage, type, name, ident);
988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err < NO_ERROR) {
989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!localHasErrors) {
993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols != NULL) {
995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols = symbols->addNestedSymbol(String8(type), srcPos);
996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols != NULL) {
998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols->makeSymbolPublic(String8(name), srcPos);
999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String16 comment(
1000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            block.getComment(&len) ? block.getComment(&len) : nulStr);
1001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols->appendComment(String8(name), comment, srcPos);
1002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        srcPos.error("Unable to create symbols!\n");
1004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
1010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), public16.string()) == 0) {
1011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
1012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
1018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 type;
1021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
1022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (typeIdx < 0) {
1023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'type' attribute is required for <public-padding>\n");
1024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                type = String16(block.getAttributeStringValue(typeIdx, &len));
1027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 name;
1029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (nameIdx < 0) {
1031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'name' attribute is required for <public-padding>\n");
1032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                name = String16(block.getAttributeStringValue(nameIdx, &len));
1035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                uint32_t start = 0;
1037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t startIdx = block.indexOfAttribute(NULL, "start");
1038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (startIdx >= 0) {
1039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    const char16_t* startStr = block.getAttributeStringValue(startIdx, &len);
1040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Res_value startValue;
1041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!ResTable::stringToInt(startStr, len, &startValue)) {
1042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        srcPos.error("Given 'start' attribute is not an integer: %s\n",
1043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String8(block.getAttributeStringValue(startIdx, &len)).string());
1044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        start = startValue.data;
1047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (nextPublicId.indexOfKey(type) < 0) {
1049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("No 'start' attribute supplied <public-padding>,"
1050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            " and no previous id defined in this file.\n");
1051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else if (!localHasErrors) {
1053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    start = nextPublicId.valueFor(type);
1054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                uint32_t end = 0;
1057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t endIdx = block.indexOfAttribute(NULL, "end");
1058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (endIdx >= 0) {
1059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    const char16_t* endStr = block.getAttributeStringValue(endIdx, &len);
1060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Res_value endValue;
1061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!ResTable::stringToInt(endStr, len, &endValue)) {
1062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        srcPos.error("Given 'end' attribute is not an integer: %s\n",
1063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String8(block.getAttributeStringValue(endIdx, &len)).string());
1064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        end = endValue.data;
1067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("No 'end' attribute supplied <public-padding>\n");
1070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (end >= start) {
1074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    nextPublicId.replaceValueFor(type, end+1);
1075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("Padding start '%ul' is after end '%ul'\n",
1077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            start, end);
1078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 comment(
1082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    block.getComment(&len) ? block.getComment(&len) : nulStr);
1083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (uint32_t curIdent=start; curIdent<=end; curIdent++) {
1084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (localHasErrors) {
1085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        break;
1086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16 curName(name);
1088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    char buf[64];
1089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sprintf(buf, "%d", (int)(end-curIdent+1));
1090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    curName.append(String16(buf));
1091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    err = outTable->addEntry(srcPos, myPackage, type, curName,
1093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                             String16("padding"), NULL, &curParams, false,
1094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                             ResTable_map::TYPE_STRING, overwrite);
1095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err < NO_ERROR) {
1096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        break;
1098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    err = outTable->addPublic(srcPos, myPackage, type,
1100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            curName, curIdent);
1101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err < NO_ERROR) {
1102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        break;
1104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
1106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols != NULL) {
1107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols = symbols->addNestedSymbol(String8(type), srcPos);
1108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols != NULL) {
1110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols->makeSymbolPublic(String8(curName), srcPos);
1111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols->appendComment(String8(curName), comment, srcPos);
1112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        srcPos.error("Unable to create symbols!\n");
1114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
1120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
1121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
1122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
1128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 pkg;
1129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t pkgIdx = block.indexOfAttribute(NULL, "package");
1130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (pkgIdx < 0) {
1131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "A 'package' attribute is required for <private-symbols>\n");
1133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                pkg = String16(block.getAttributeStringValue(pkgIdx, &len));
1136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!localHasErrors) {
113778713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
113878713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                            "<private-symbols> is deprecated. Use the command line flag "
113978713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                            "--private-symbols instead.\n");
114078713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                    if (assets->havePrivateSymbols()) {
114178713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                        SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
114278713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                                "private symbol package already specified. Ignoring...\n");
114378713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                    } else {
114478713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                        assets->setSymbolsPrivatePackage(String8(pkg));
114578713998f94a2cc2562aa0ae7761bbc563d8eafaAdam Lesinski                    }
1146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
1150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
1151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
1152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
1158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 type;
1161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
1162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (typeIdx < 0) {
1163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'type' attribute is required for <public>\n");
1164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                type = String16(block.getAttributeStringValue(typeIdx, &len));
1167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 name;
1169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (nameIdx < 0) {
1171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'name' attribute is required for <public>\n");
1172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                name = String16(block.getAttributeStringValue(nameIdx, &len));
1175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<AaptSymbols> symbols = assets->getJavaSymbolsFor(String8("R"));
1177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (symbols != NULL) {
1178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    symbols = symbols->addNestedSymbol(String8(type), srcPos);
1179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (symbols != NULL) {
1181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    symbols->makeSymbolJavaSymbol(String8(name), srcPos);
1182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16 comment(
1183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        block.getComment(&len) ? block.getComment(&len) : nulStr);
1184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    symbols->appendComment(String8(name), comment, srcPos);
1185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("Unable to create symbols!\n");
1187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
1192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
1193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
1194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
1201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 typeName;
1204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
1205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (typeIdx < 0) {
1206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'type' attribute is required for <add-resource>\n");
1207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                typeName = String16(block.getAttributeStringValue(typeIdx, &len));
1210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 name;
1212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (nameIdx < 0) {
1214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'name' attribute is required for <add-resource>\n");
1215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                name = String16(block.getAttributeStringValue(nameIdx, &len));
1218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outTable->canAddEntry(srcPos, myPackage, typeName, name);
1220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::END_TAG) {
1223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
1224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
1225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
1231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 ident;
1234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t identIdx = block.indexOfAttribute(NULL, "name");
1235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (identIdx < 0) {
1236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    srcPos.error("A 'name' attribute is required for <declare-styleable>\n");
1237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ident = String16(block.getAttributeStringValue(identIdx, &len));
1240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
1242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!localHasErrors) {
1243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols != NULL) {
1244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols = symbols->addNestedSymbol(String8("styleable"), srcPos);
1245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<AaptSymbols> styleSymbols = symbols;
1247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols != NULL) {
1248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        symbols = symbols->addNestedSymbol(String8(ident), srcPos);
1249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (symbols == NULL) {
1251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        srcPos.error("Unable to create symbols!\n");
1252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        return UNKNOWN_ERROR;
1253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16 comment(
1256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        block.getComment(&len) ? block.getComment(&len) : nulStr);
1257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    styleSymbols->appendComment(String8(ident), comment, srcPos);
1258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    symbols = NULL;
1260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::START_TAG) {
1264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
1265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            while ((code=block.next()) != ResXMLTree::END_DOCUMENT
1266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                   && code != ResXMLTree::BAD_DOCUMENT) {
1267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (code == ResXMLTree::END_TAG) {
1268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
1269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        break;
1270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            continue;
1274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
1275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            while ((code=block.next()) != ResXMLTree::END_DOCUMENT
1276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                   && code != ResXMLTree::BAD_DOCUMENT) {
1277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (code == ResXMLTree::END_TAG) {
1278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
1279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        break;
1280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    }
1281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            continue;
1284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (strcmp16(block.getElementName(&len), attr16.string()) != 0) {
1285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    "Tag <%s> can not appear inside <declare-styleable>, only <attr>\n",
1287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    String8(block.getElementName(&len)).string());
1288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            return UNKNOWN_ERROR;
1289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String16 comment(
1292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            block.getComment(&len) ? block.getComment(&len) : nulStr);
1293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String16 itemIdent;
1294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        err = compileAttribute(in, block, myPackage, outTable, &itemIdent, true);
1295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (err != NO_ERROR) {
1296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasErrors = localHasErrors = true;
1297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (symbols != NULL) {
1300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            SourcePos srcPos(String8(in->getPrintableSource()), block.getLineNumber());
1301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            symbols->addSymbol(String8(itemIdent), 0, srcPos);
1302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            symbols->appendComment(String8(itemIdent), comment, srcPos);
1303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            //printf("Attribute %s comment: %s\n", String8(itemIdent).string(),
1304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            //     String8(comment).string());
1305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (code == ResXMLTree::END_TAG) {
1307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
1308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            break;
1309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                "Found tag </%s> where </attr> is expected\n",
1313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String8(block.getElementName(&len)).string());
1314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        return UNKNOWN_ERROR;
1315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), attr16.string()) == 0) {
1320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = compileAttribute(in, block, myPackage, outTable, NULL);
1321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err != NO_ERROR) {
1322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = true;
1323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), item16.string()) == 0) {
1327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &item16;
1328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t attri = block.indexOfAttribute(NULL, "type");
1329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (attri >= 0) {
1330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    curType = String16(block.getAttributeStringValue(attri, &len));
13315892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
13325892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    if (nameIdx >= 0) {
13335892248580859620db90d5ef2e3c2f48531933faAdrian Roos                        curName = String16(block.getAttributeStringValue(nameIdx, &len));
13345892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    }
1335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
1336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (formatIdx >= 0) {
1337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String16 formatStr = String16(block.getAttributeStringValue(
1338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                formatIdx, &len));
1339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        curFormat = parse_flags(formatStr.string(), formatStr.size(),
1340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                gFormatFlags);
1341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (curFormat == 0) {
1342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    "Tag <item> 'format' attribute value \"%s\" not valid\n",
1344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    String8(formatStr).string());
1345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasErrors = localHasErrors = true;
1346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "A 'type' attribute is required for <item>\n");
1351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsStyled = true;
1354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), string16.string()) == 0) {
1355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Note the existence and locale of every string we process
135691447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath                char rawLocale[RESTABLE_MAX_LOCALE_LEN];
135791447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath                curParams.getBcp47Locale(rawLocale);
1358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 locale(rawLocale);
1359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 name;
1360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 translatable;
1361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 formatted;
1362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                size_t n = block.getAttributeCount();
1364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t i = 0; i < n; i++) {
1365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    size_t length;
1366f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert                    const char16_t* attr = block.getAttributeName(i, &length);
1367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (strcmp16(attr, name16.string()) == 0) {
1368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        name.setTo(block.getAttributeStringValue(i, &length));
1369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (strcmp16(attr, translatable16.string()) == 0) {
1370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        translatable.setTo(block.getAttributeStringValue(i, &length));
1371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (strcmp16(attr, formatted16.string()) == 0) {
1372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        formatted.setTo(block.getAttributeStringValue(i, &length));
1373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (name.size() > 0) {
13775892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    if (locale.size() == 0) {
13785892248580859620db90d5ef2e3c2f48531933faAdrian Roos                        outTable->addDefaultLocalization(name);
13795892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    }
1380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (translatable == false16) {
1381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        curIsFormatted = false;
1382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // Untranslatable strings must only exist in the default [empty] locale
1383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (locale.size() > 0) {
1384a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                            SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
1385a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                                    "string '%s' marked untranslatable but exists in locale '%s'\n",
1386a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                                    String8(name).string(),
1387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    locale.string());
1388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            // hasErrors = localHasErrors = true;
1389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            // Intentionally empty block:
1391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            //
1392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            // Don't add untranslatable strings to the localization table; that
1393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            // way if we later see localizations of them, they'll be flagged as
1394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            // having no default translation.
1395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
1397a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                        outTable->addLocalization(
1398a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                                name,
1399a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                                locale,
1400a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                                SourcePos(in->getPrintableSource(), block.getLineNumber()));
1401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (formatted == false16) {
1404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        curIsFormatted = false;
1405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &string16;
1409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = string16;
1410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
1411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsStyled = true;
141284410b054c7db0b6685a0f15cb2d1ffcb264f6c9Igor Viarheichyk                curIsPseudolocalizable = fileIsTranslatable && (translatable != false16);
1413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) {
1414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &drawable16;
1415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = drawable16;
1416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
1417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), color16.string()) == 0) {
1418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &color16;
1419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = color16;
1420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
1421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), bool16.string()) == 0) {
1422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &bool16;
1423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = bool16;
1424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_BOOLEAN;
1425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), integer16.string()) == 0) {
1426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &integer16;
1427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = integer16;
1428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
1429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), dimen16.string()) == 0) {
1430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &dimen16;
1431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = dimen16;
1432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_DIMENSION;
1433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), fraction16.string()) == 0) {
1434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &fraction16;
1435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = fraction16;
1436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_FRACTION;
1437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), bag16.string()) == 0) {
1438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &bag16;
1439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBag = true;
1440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t attri = block.indexOfAttribute(NULL, "type");
1441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (attri >= 0) {
1442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    curType = String16(block.getAttributeStringValue(attri, &len));
1443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "A 'type' attribute is required for <bag>\n");
1446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), style16.string()) == 0) {
1449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &style16;
1450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = style16;
1451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBag = true;
1452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), plurals16.string()) == 0) {
1453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &plurals16;
1454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = plurals16;
1455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBag = true;
1456a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                curIsPseudolocalizable = fileIsTranslatable;
1457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), array16.string()) == 0) {
1458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &array16;
1459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = array16;
1460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBag = true;
1461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBagReplaceOnOverwrite = true;
1462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
1463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (formatIdx >= 0) {
1464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16 formatStr = String16(block.getAttributeStringValue(
1465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            formatIdx, &len));
1466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    curFormat = parse_flags(formatStr.string(), formatStr.size(),
1467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            gFormatFlags);
1468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (curFormat == 0) {
1469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                "Tag <array> 'format' attribute value \"%s\" not valid\n",
1471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String8(formatStr).string());
1472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) {
1476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Check whether these strings need valid formats.
1477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // (simplified form of what string16 does above)
1478a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                bool isTranslatable = false;
1479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                size_t n = block.getAttributeCount();
14809a9fa163c384e7fff159d339dfcce3b3122bece5Narayan Kamath
14819a9fa163c384e7fff159d339dfcce3b3122bece5Narayan Kamath                // Pseudolocalizable by default, unless this string array isn't
14829a9fa163c384e7fff159d339dfcce3b3122bece5Narayan Kamath                // translatable.
1483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t i = 0; i < n; i++) {
1484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    size_t length;
1485f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert                    const char16_t* attr = block.getAttributeName(i, &length);
1486a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                    if (strcmp16(attr, formatted16.string()) == 0) {
1487f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert                        const char16_t* value = block.getAttributeStringValue(i, &length);
14889a9fa163c384e7fff159d339dfcce3b3122bece5Narayan Kamath                        if (strcmp16(value, false16.string()) == 0) {
1489a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            curIsFormatted = false;
14909a9fa163c384e7fff159d339dfcce3b3122bece5Narayan Kamath                        }
1491a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                    } else if (strcmp16(attr, translatable16.string()) == 0) {
1492f348c15ecf78e9d58b8238ffcf1d78a279e3a862Dan Albert                        const char16_t* value = block.getAttributeStringValue(i, &length);
1493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(value, false16.string()) == 0) {
1494a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            isTranslatable = false;
1495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &string_array16;
1500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = array16;
1501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
1502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBag = true;
1503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBagReplaceOnOverwrite = true;
1504a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                curIsPseudolocalizable = isTranslatable && fileIsTranslatable;
1505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) {
1506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curTag = &integer_array16;
1507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curType = array16;
1508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
1509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBag = true;
1510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                curIsBagReplaceOnOverwrite = true;
1511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "Found tag %s where item is expected\n",
1514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(block.getElementName(&len)).string());
1515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
1516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 ident;
1519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ssize_t identIdx = block.indexOfAttribute(NULL, "name");
1520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (identIdx >= 0) {
1521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ident = String16(block.getAttributeStringValue(identIdx, &len));
1522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "A 'name' attribute is required for <%s>\n",
1525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(*curTag).string());
1526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                hasErrors = localHasErrors = true;
1527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 product;
1530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            identIdx = block.indexOfAttribute(NULL, "product");
1531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (identIdx >= 0) {
1532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                product = String16(block.getAttributeStringValue(identIdx, &len));
1533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 comment(block.getComment(&len) ? block.getComment(&len) : nulStr);
1536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (curIsBag) {
1538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Figure out the parent of this bag...
1539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 parentIdent;
1540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t parentIdentIdx = block.indexOfAttribute(NULL, "parent");
1541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (parentIdentIdx >= 0) {
1542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    parentIdent = String16(block.getAttributeStringValue(parentIdentIdx, &len));
1543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
1544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ssize_t sep = ident.findLast('.');
1545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (sep >= 0) {
1546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        parentIdent.setTo(ident, sep);
1547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!localHasErrors) {
1551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    err = outTable->startBag(SourcePos(in->getPrintableSource(),
1552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            block.getLineNumber()), myPackage, curType, ident,
1553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            parentIdent, &curParams,
1554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            overwrite, curIsBagReplaceOnOverwrite);
1555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err != NO_ERROR) {
1556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        hasErrors = localHasErrors = true;
1557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ssize_t elmIndex = 0;
1561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                char elmIndexStr[14];
1562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                while ((code=block.next()) != ResXMLTree::END_DOCUMENT
1563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        && code != ResXMLTree::BAD_DOCUMENT) {
1564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (code == ResXMLTree::START_TAG) {
1566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), item16.string()) != 0) {
1567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    "Tag <%s> can not appear inside <%s>, only <item>\n",
1569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    String8(block.getElementName(&len)).string(),
1570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    String8(*curTag).string());
1571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            return UNKNOWN_ERROR;
1572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String16 itemIdent;
1575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (curType == array16) {
1576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            sprintf(elmIndexStr, "^index_%d", (int)elmIndex++);
1577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            itemIdent = String16(elmIndexStr);
1578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else if (curType == plurals16) {
1579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "quantity");
1580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (itemIdentIdx >= 0) {
1581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String16 quantity16(block.getAttributeStringValue(itemIdentIdx, &len));
1582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                if (quantity16 == other16) {
1583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    itemIdent = quantityOther16;
1584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                else if (quantity16 == zero16) {
1586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    itemIdent = quantityZero16;
1587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                else if (quantity16 == one16) {
1589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    itemIdent = quantityOne16;
1590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                else if (quantity16 == two16) {
1592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    itemIdent = quantityTwo16;
1593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                else if (quantity16 == few16) {
1595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    itemIdent = quantityFew16;
1596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                else if (quantity16 == many16) {
1598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    itemIdent = quantityMany16;
1599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                else {
1601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            "Illegal 'quantity' attribute is <item> inside <plurals>\n");
1603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    hasErrors = localHasErrors = true;
1604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                }
1605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else {
1606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        "A 'quantity' attribute is required for <item> inside <plurals>\n");
1608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasErrors = localHasErrors = true;
1609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        } else {
1611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "name");
1612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (itemIdentIdx >= 0) {
1613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                itemIdent = String16(block.getAttributeStringValue(itemIdentIdx, &len));
1614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            } else {
1615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        "A 'name' attribute is required for <item>\n");
1617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                hasErrors = localHasErrors = true;
1618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ResXMLParser::ResXMLPosition parserPosition;
1622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        block.getPosition(&parserPosition);
1623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
1625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                ident, parentIdent, itemIdent, curFormat, curIsFormatted,
1626a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                product, NO_PSEUDOLOCALIZATION, overwrite, outTable);
1627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (err == NO_ERROR) {
1628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            if (curIsPseudolocalizable && localeIsDefined(curParams)
1629a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    && bundle->getPseudolocalize() > 0) {
1630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                // pseudolocalize here
1631a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) ==
1632a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                   PSEUDO_ACCENTED) {
1633a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    block.setPosition(parserPosition);
1634a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
1635a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                            curType, ident, parentIdent, itemIdent, curFormat,
1636a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                            curIsFormatted, product, PSEUDO_ACCENTED,
1637a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                            overwrite, outTable);
1638a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                }
1639a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                if ((PSEUDO_BIDI & bundle->getPseudolocalize()) ==
1640a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                   PSEUDO_BIDI) {
1641a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    block.setPosition(parserPosition);
1642a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    err = parseAndAddBag(bundle, in, &block, pseudoBidiParams, myPackage,
1643a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                            curType, ident, parentIdent, itemIdent, curFormat,
1644a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                            curIsFormatted, product, PSEUDO_BIDI,
1645a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                            overwrite, outTable);
1646a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                }
1647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
1648a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        }
1649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (err != NO_ERROR) {
1650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasErrors = localHasErrors = true;
1651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else if (code == ResXMLTree::END_TAG) {
1653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (strcmp16(block.getElementName(&len), curTag->string()) != 0) {
1654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    "Found tag </%s> where </%s> is expected\n",
1656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    String8(block.getElementName(&len)).string(),
1657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    String8(*curTag).string());
1658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            return UNKNOWN_ERROR;
1659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        break;
1661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
1664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ResXMLParser::ResXMLPosition parserPosition;
1665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                block.getPosition(&parserPosition);
1666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
1668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        *curTag, curIsStyled, curFormat, curIsFormatted,
1669a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        product, NO_PSEUDOLOCALIZATION, overwrite, &skippedResourceNames, outTable);
1670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
1672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasErrors = localHasErrors = true;
1673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                else if (err == NO_ERROR) {
16755892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    if (curType == string16 && !curParams.language[0] && !curParams.country[0]) {
16765892248580859620db90d5ef2e3c2f48531933faAdrian Roos                        outTable->addDefaultLocalization(curName);
16775892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    }
1678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (curIsPseudolocalizable && localeIsDefined(curParams)
1679a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            && bundle->getPseudolocalize() > 0) {
1680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // pseudolocalize here
1681a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) ==
1682a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                           PSEUDO_ACCENTED) {
1683a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            block.setPosition(parserPosition);
1684a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
1685a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    ident, *curTag, curIsStyled, curFormat,
1686a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    curIsFormatted, product,
1687a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    PSEUDO_ACCENTED, overwrite, &skippedResourceNames, outTable);
1688a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        }
1689a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        if ((PSEUDO_BIDI & bundle->getPseudolocalize()) ==
1690a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                           PSEUDO_BIDI) {
1691a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            block.setPosition(parserPosition);
1692a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                            err = parseAndAddEntry(bundle, in, &block, pseudoBidiParams,
1693a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    myPackage, curType, ident, *curTag, curIsStyled, curFormat,
1694a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    curIsFormatted, product,
1695a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                                    PSEUDO_BIDI, overwrite, &skippedResourceNames, outTable);
1696a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                        }
1697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (err != NO_ERROR) {
1698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            hasErrors = localHasErrors = true;
1699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
1700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
1701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
1705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (comment.size() > 0) {
1706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).string(),
1707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       String8(curType).string(), String8(ident).string(),
1708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       String8(comment).string());
1709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
1711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!localHasErrors) {
1712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outTable->appendComment(myPackage, curType, ident, comment, false);
1713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else if (code == ResXMLTree::END_TAG) {
1716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strcmp16(block.getElementName(&len), resources16.string()) != 0) {
1717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "Unexpected end tag %s\n", String8(block.getElementName(&len)).string());
1719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
1720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else if (code == ResXMLTree::START_NAMESPACE || code == ResXMLTree::END_NAMESPACE) {
1723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        else if (code == ResXMLTree::TEXT) {
1725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (isWhitespace(block.getText(&len))) {
1726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
1727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    "Found text \"%s\" where item tag is expected\n",
1730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(block.getText(&len)).string());
1731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
1732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17358ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // For every resource defined, there must be exist one variant with a product attribute
17368ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // set to 'default' (or no product attribute at all).
17378ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // We check to see that for every resource that was ignored because of a mismatched
17388ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    // product attribute, some product variant of that resource was processed.
17398ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    for (size_t i = 0; i < skippedResourceNames.size(); i++) {
17408ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        if (skippedResourceNames[i]) {
17418ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski            const type_ident_pair_t& p = skippedResourceNames.keyAt(i);
17428ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski            if (!outTable->hasBagOrEntry(myPackage, p.type, p.ident)) {
17438ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                const char* bundleProduct =
17448ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        (bundle->getProduct() == NULL) ? "" : bundle->getProduct();
17458ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                fprintf(stderr, "In resource file %s: %s\n",
17468ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        in->getPrintableSource().string(),
17478ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        curParams.toString().string());
17488ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski
17498ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                fprintf(stderr, "\t%s '%s' does not match product %s.\n"
17508ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        "\tYou may have forgotten to include a 'default' product variant"
17518ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        " of the resource.\n",
17528ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        String8(p.type).string(), String8(p.ident).string(),
17538ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                        bundleProduct[0] == 0 ? "default" : bundleProduct);
17548ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                return UNKNOWN_ERROR;
17558ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski            }
17568ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski        }
17578ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski    }
17588ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski
17592412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
1760282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1761282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1762833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam LesinskiResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type)
1763833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    : mAssetsPackage(assetsPackage)
1764833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    , mPackageType(type)
1765833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    , mTypeIdOffset(0)
1766833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    , mNumLocal(0)
1767833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    , mBundle(bundle)
1768833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski{
1769833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    ssize_t packageId = -1;
1770833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    switch (mPackageType) {
1771833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        case App:
1772833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        case AppFeature:
1773833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            packageId = 0x7f;
1774833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            break;
1775833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1776833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        case System:
1777833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            packageId = 0x01;
1778833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            break;
1779833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1780833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        case SharedLibrary:
1781833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            packageId = 0x00;
1782833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            break;
1783833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1784833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        default:
1785833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            assert(0);
1786833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            break;
1787833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    }
1788833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    sp<Package> package = new Package(mAssetsPackage, packageId);
1789833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    mPackages.add(assetsPackage, package);
1790833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    mOrderedPackages.add(package);
1791833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1792833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    // Every resource table always has one first entry, the bag attributes.
1793833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    const SourcePos unknown(String8("????"), 0);
1794833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    getType(mAssetsPackage, String16("attr"), unknown);
1795833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski}
1796833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1797833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinskistatic uint32_t findLargestTypeIdForPackage(const ResTable& table, const String16& packageName) {
1798833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    const size_t basePackageCount = table.getBasePackageCount();
1799833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    for (size_t i = 0; i < basePackageCount; i++) {
1800833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        if (packageName == table.getBasePackageName(i)) {
1801833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            return table.getLastTypeIdForPackage(i);
1802833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        }
1803833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    }
1804833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    return 0;
1805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets)
1808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = assets->buildIncludedResources(bundle);
1810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
1811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
1812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mAssets = assets;
1815833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    mTypeIdOffset = findLargestTypeIdForPackage(assets->getIncludedResources(), mAssetsPackage);
1816833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1817833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    const String8& featureAfter = bundle->getFeatureAfterPackage();
1818833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    if (!featureAfter.isEmpty()) {
1819833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        AssetManager featureAssetManager;
1820833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        if (!featureAssetManager.addAssetPath(featureAfter, NULL)) {
1821833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            fprintf(stderr, "ERROR: Feature package '%s' not found.\n",
1822833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                    featureAfter.string());
1823833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            return UNKNOWN_ERROR;
1824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1826833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        const ResTable& featureTable = featureAssetManager.getResources(false);
1827030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert        mTypeIdOffset = std::max(mTypeIdOffset,
1828833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                findLargestTypeIdForPackage(featureTable, mAssetsPackage));
1829833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    }
1830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
1832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::addPublic(const SourcePos& sourcePos,
1835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& package,
1836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& type,
1837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& name,
1838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const uint32_t ident)
1839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
1841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        .identifierForName(name.string(), name.size(),
1842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           type.string(), type.size(),
1843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           package.string(), package.size());
1844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
1845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sourcePos.error("Error declaring public resource %s/%s for included package %s\n",
1846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8(type).string(), String8(name).string(),
1847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8(package).string());
1848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = getType(package, type, sourcePos);
1852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (t == NULL) {
1853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return t->addPublic(sourcePos, name, ident);
1856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::addEntry(const SourcePos& sourcePos,
1859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& package,
1860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& type,
1861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& name,
1862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& value,
1863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const Vector<StringPool::entry_style_span>* style,
1864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const ResTable_config* params,
1865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const bool doSetIndex,
1866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const int32_t format,
1867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const bool overwrite)
1868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
1870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        .identifierForName(name.string(), name.size(),
1871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           type.string(), type.size(),
1872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           package.string(), package.size());
1873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
1874833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        sourcePos.error("Resource entry %s/%s is already defined in package %s.",
1875833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                String8(type).string(), String8(name).string(), String8(package).string());
1876833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        return UNKNOWN_ERROR;
1877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Entry> e = getEntry(package, type, name, sourcePos, overwrite,
1880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           params, doSetIndex);
1881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e == NULL) {
1882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = e->setItem(sourcePos, value, style, format, overwrite);
1885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err == NO_ERROR) {
1886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mNumLocal++;
1887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
1889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::startBag(const SourcePos& sourcePos,
1892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& package,
1893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& type,
1894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& name,
1895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& bagParent,
1896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const ResTable_config* params,
1897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 bool overlay,
18982412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                                 bool replace, bool /* isId */)
1899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t result = NO_ERROR;
1901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Check for adding entries in other packages...  for now we do
1903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // nothing.  We need to do the right thing here to support skinning.
1904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
1905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    .identifierForName(name.string(), name.size(),
1906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       type.string(), type.size(),
1907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       package.string(), package.size());
1908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
1909833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        sourcePos.error("Resource entry %s/%s is already defined in package %s.",
1910833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                String8(type).string(), String8(name).string(), String8(package).string());
1911833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        return UNKNOWN_ERROR;
1912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1913833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
1914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (overlay && !mBundle->getAutoAddOverlay() && !hasBagOrEntry(package, type, name)) {
1915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool canAdd = false;
1916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Package> p = mPackages.valueFor(package);
1917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (p != NULL) {
1918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getTypes().valueFor(type);
1919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t != NULL) {
1920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (t->getCanAddEntries().indexOf(name) >= 0) {
1921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    canAdd = true;
1922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
1923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
1924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!canAdd) {
1926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
1927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8(name).string());
1928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
1929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
1930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
1932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e == NULL) {
1933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If a parent is explicitly specified, set it.
1937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bagParent.size() > 0) {
1938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        e->setParent(bagParent);
1939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ((result = e->makeItABag(sourcePos)) != NO_ERROR) {
1942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return result;
1943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (overlay && replace) {
1946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return e->emptyBag(sourcePos);
1947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
1949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::addBag(const SourcePos& sourcePos,
1952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const String16& package,
1953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const String16& type,
1954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const String16& name,
1955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const String16& bagParent,
1956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const String16& bagKey,
1957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const String16& value,
1958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const Vector<StringPool::entry_style_span>* style,
1959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               const ResTable_config* params,
1960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                               bool replace, bool isId, const int32_t format)
1961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
1962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Check for adding entries in other packages...  for now we do
1963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // nothing.  We need to do the right thing here to support skinning.
1964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
1965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        .identifierForName(name.string(), name.size(),
1966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           type.string(), type.size(),
1967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           package.string(), package.size());
1968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
1969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_ERROR;
1970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 0
1973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (name == String16("left")) {
1974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Adding bag left: file=%s, line=%d, type=%s\n",
1975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski               sourcePos.file.striing(), sourcePos.line, String8(type).string());
1976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
1978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params);
1979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e == NULL) {
1980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
1981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // If a parent is explicitly specified, set it.
1984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bagParent.size() > 0) {
1985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        e->setParent(bagParent);
1986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const bool first = e->getBag().indexOfKey(bagKey) < 0;
1989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = e->addToBag(sourcePos, bagKey, value, style, replace, isId, format);
1990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err == NO_ERROR && first) {
1991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mNumLocal++;
1992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
1993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
1994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
1995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
1996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::hasBagOrEntry(const String16& package,
1997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& type,
1998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& name) const
1999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // First look for this in the included resources...
2001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
2002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        .identifierForName(name.string(), name.size(),
2003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           type.string(), type.size(),
2004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           package.string(), package.size());
2005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
2006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p = mPackages.valueFor(package);
2010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p != NULL) {
2011282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Type> t = p->getTypes().valueFor(type);
2012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (t != NULL) {
2013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<ConfigList> c =  t->getConfigs().valueFor(name);
2014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (c != NULL) return true;
2015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::hasBagOrEntry(const String16& package,
2022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& type,
2023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& name,
2024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const ResTable_config& config) const
2025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // First look for this in the included resources...
2027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
2028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        .identifierForName(name.string(), name.size(),
2029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           type.string(), type.size(),
2030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           package.string(), package.size());
2031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
2032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p = mPackages.valueFor(package);
2036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p != NULL) {
2037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Type> t = p->getTypes().valueFor(type);
2038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (t != NULL) {
2039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<ConfigList> c =  t->getConfigs().valueFor(name);
2040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (c != NULL) {
2041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<Entry> e = c->getEntries().valueFor(config);
2042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (e != NULL) {
2043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return true;
2044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::hasBagOrEntry(const String16& ref,
2053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16* defType,
2054282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16* defPackage)
2055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 package, type, name;
2057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!ResTable::expandResourceRef(ref.string(), ref.size(), &package, &type, &name,
2058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                defType, defPackage ? defPackage:&mAssetsPackage, NULL)) {
2059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return false;
2060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return hasBagOrEntry(package, type, name);
2062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::appendComment(const String16& package,
2065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& type,
2066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& name,
2067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& comment,
2068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bool onlyIfEmpty)
2069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (comment.size() <= 0) {
2071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p = mPackages.valueFor(package);
2075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p != NULL) {
2076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Type> t = p->getTypes().valueFor(type);
2077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (t != NULL) {
2078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<ConfigList> c =  t->getConfigs().valueFor(name);
2079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (c != NULL) {
2080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                c->appendComment(comment, onlyIfEmpty);
2081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return true;
2082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::appendTypeComment(const String16& package,
2089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                      const String16& type,
2090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                      const String16& name,
2091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                      const String16& comment)
2092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (comment.size() <= 0) {
2094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p = mPackages.valueFor(package);
2098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p != NULL) {
2099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Type> t = p->getTypes().valueFor(type);
2100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (t != NULL) {
2101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<ConfigList> c =  t->getConfigs().valueFor(name);
2102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (c != NULL) {
2103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                c->appendTypeComment(comment);
2104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return true;
2105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2111afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinskibool ResourceTable::makeAttribute(const String16& package,
2112afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                                  const String16& name,
2113afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                                  const SourcePos& source,
2114afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                                  int32_t format,
2115afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                                  const String16& comment,
2116afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                                  bool shouldAppendComment) {
2117afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    const String16 attr16("attr");
2118afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski
2119afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    // First look for this in the included resources...
2120afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
2121afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski            .identifierForName(name.string(), name.size(),
2122afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                               attr16.string(), attr16.size(),
2123afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                               package.string(), package.size());
2124afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    if (rid != 0) {
2125afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        source.error("Attribute \"%s\" has already been defined", String8(name).string());
2126afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        return false;
2127afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    }
2128afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski
2129afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    sp<ResourceTable::Entry> entry = getEntry(package, attr16, name, source, false);
2130afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    if (entry == NULL) {
2131afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        source.error("Failed to create entry attr/%s", String8(name).string());
2132afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        return false;
2133afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    }
2134afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski
2135afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    if (entry->makeItABag(source) != NO_ERROR) {
2136afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        return false;
2137afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    }
2138afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski
2139afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    const String16 formatKey16("^type");
2140afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    const String16 formatValue16(String8::format("%d", format));
2141afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski
2142afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    ssize_t idx = entry->getBag().indexOfKey(formatKey16);
2143afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    if (idx >= 0) {
2144afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        // We have already set a format for this attribute, check if they are different.
2145afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        // We allow duplicate attribute definitions so long as they are identical.
2146afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        // This is to ensure inter-operation with libraries that define the same generic attribute.
2147afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        const Item& formatItem = entry->getBag().valueAt(idx);
2148afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        if ((format & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) ||
2149afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                formatItem.value != formatValue16) {
2150afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski            source.error("Attribute \"%s\" already defined with incompatible format.\n"
2151afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                         "%s:%d: Original attribute defined here.",
2152afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                         String8(name).string(), formatItem.sourcePos.file.string(),
2153afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski                         formatItem.sourcePos.line);
2154afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski            return false;
2155afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        }
2156afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    } else {
2157afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        entry->addToBag(source, formatKey16, formatValue16);
2158afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        // Increment the number of resources we have. This is used to determine if we should
2159afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        // even generate a resource table.
2160afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski        mNumLocal++;
2161afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    }
2162afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    appendComment(package, attr16, name, comment, shouldAppendComment);
2163afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski    return true;
2164afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski}
2165afc79be228596c56ea68c0d2fa22d0a8d733be47Adam Lesinski
2166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::canAddEntry(const SourcePos& pos,
2167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16& package, const String16& type, const String16& name)
2168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = getType(package, type, pos);
2170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (t != NULL) {
2171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        t->canAddEntry(name);
2172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisize_t ResourceTable::size() const {
2176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return mPackages.size();
2177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisize_t ResourceTable::numLocalResources() const {
2180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return mNumLocal;
2181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::hasResources() const {
2184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return mNumLocal > 0;
2185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
218727f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinskisp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
218827f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski        const bool isBase)
2189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
219127f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski    status_t err = flatten(bundle, filter, data, isBase);
2192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err == NO_ERROR ? data : NULL;
2193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiinline uint32_t ResourceTable::getResId(const sp<Package>& p,
2196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        const sp<Type>& t,
2197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        uint32_t nameId)
2198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return makeResId(p->getAssignedId(), t->getIndex(), nameId);
2200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiuint32_t ResourceTable::getResId(const String16& package,
2203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& type,
2204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16& name,
2205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 bool onlyPublic) const
2206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t id = ResourceIdCache::lookup(package, type, name, onlyPublic);
2208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (id != 0) return id;     // cache hit
2209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // First look for this in the included resources...
2211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t specFlags = 0;
2212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t rid = mAssets->getIncludedResources()
2213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        .identifierForName(name.string(), name.size(),
2214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           type.string(), type.size(),
2215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           package.string(), package.size(),
2216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           &specFlags);
2217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (rid != 0) {
2218fa1e9d7ad0e3f5b7fce37dbdc3f5ad889274ee43Adam Lesinski        if (onlyPublic && (specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
2219fa1e9d7ad0e3f5b7fce37dbdc3f5ad889274ee43Adam Lesinski            // If this is a feature split and the resource has the same
2220fa1e9d7ad0e3f5b7fce37dbdc3f5ad889274ee43Adam Lesinski            // package name as us, then everything is public.
2221fa1e9d7ad0e3f5b7fce37dbdc3f5ad889274ee43Adam Lesinski            if (mPackageType != AppFeature || mAssetsPackage != package) {
2222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return 0;
2223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2226833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        return ResourceIdCache::store(package, type, name, onlyPublic, rid);
2227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2229833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    sp<Package> p = mPackages.valueFor(package);
2230833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    if (p == NULL) return 0;
2231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = p->getTypes().valueFor(type);
2232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (t == NULL) return 0;
22339b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    sp<ConfigList> c = t->getConfigs().valueFor(name);
22349b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    if (c == NULL) {
22359b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (type != String16("attr")) {
22369b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            return 0;
22379b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
22389b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        t = p->getTypes().valueFor(String16(kAttrPrivateType));
22399b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (t == NULL) return 0;
22409b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        c = t->getConfigs().valueFor(name);
22419b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (c == NULL) return 0;
22429b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
2243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int32_t ei = c->getEntryIndex();
2244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ei < 0) return 0;
2245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return ResourceIdCache::store(package, type, name, onlyPublic,
2247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            getResId(p, t, ei));
2248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiuint32_t ResourceTable::getResId(const String16& ref,
2251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16* defType,
2252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const String16* defPackage,
2253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 const char** outErrorMsg,
2254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                 bool onlyPublic) const
2255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 package, type, name;
2257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool refOnlyPublic = true;
2258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!ResTable::expandResourceRef(
2259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ref.string(), ref.size(), &package, &type, &name,
2260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        defType, defPackage ? defPackage:&mAssetsPackage,
2261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outErrorMsg, &refOnlyPublic)) {
22622412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kIsDebug) {
22632412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("Expanding resource: ref=%s\n", String8(ref).string());
22642412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("Expanding resource: defType=%s\n",
22652412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    defType ? String8(*defType).string() : "NULL");
22662412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("Expanding resource: defPackage=%s\n",
22672412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    defPackage ? String8(*defPackage).string() : "NULL");
22682412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("Expanding resource: ref=%s\n", String8(ref).string());
22692412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
22702412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    String8(package).string(), String8(type).string(),
22712412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    String8(name).string());
22722412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        }
2273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return 0;
2274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic);
22762412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kIsDebug) {
22772412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
22782412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(package).string(), String8(type).string(),
22792412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                String8(name).string(), res);
22802412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
2281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (res == 0) {
2282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outErrorMsg)
2283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outErrorMsg = "No resource found that matches the given name";
2284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return res;
2286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::isValidResourceName(const String16& s)
2289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const char16_t* p = s.string();
2291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool first = true;
2292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while (*p) {
2293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if ((*p >= 'a' && *p <= 'z')
2294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            || (*p >= 'A' && *p <= 'Z')
2295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            || *p == '_'
2296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            || (!first && *p >= '0' && *p <= '9')) {
2297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            first = false;
2298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            p++;
2299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return false;
2302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return true;
2304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
2307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const String16& str,
2308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  bool preserveSpaces, bool coerceType,
2309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  uint32_t attrID,
2310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const Vector<StringPool::entry_style_span>* style,
2311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  String16* outStr, void* accessorCookie,
2312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  uint32_t attrType, const String8* configTypeName,
2313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  const ConfigDescription* config)
2314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 finalStr;
2316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool res = true;
2318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (style == NULL || style->size() == 0) {
2319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Text is not styled so it can be any type...  let's figure it out.
2320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res = mAssets->getIncludedResources()
2321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .stringToValue(outValue, &finalStr, str.string(), str.size(), preserveSpaces,
2322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            coerceType, attrID, NULL, &mAssetsPackage, this,
2323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                           accessorCookie, attrType);
2324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
2325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Styled text can only be a string, and while collecting the style
2326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // information we have already processed that string!
2327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue->size = sizeof(Res_value);
2328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue->res0 = 0;
2329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue->dataType = outValue->TYPE_STRING;
2330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue->data = 0;
2331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        finalStr = str;
2332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!res) {
2335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return false;
2336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (outValue->dataType == outValue->TYPE_STRING) {
2339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Should do better merging styles.
2340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (pool) {
2341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 configStr;
2342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (config != NULL) {
2343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                configStr = config->toString();
2344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                configStr = "(null)";
2346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
23472412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            if (kIsDebug) {
23482412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                printf("Adding to pool string style #%zu config %s: %s\n",
23492412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        style != NULL ? style->size() : 0U,
23502412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        configStr.string(), String8(finalStr).string());
23512412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            }
2352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (style != NULL && style->size() > 0) {
2353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outValue->data = pool->add(finalStr, *style, configTypeName, config);
2354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outValue->data = pool->add(finalStr, true, configTypeName, config);
2356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
2358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Caller will fill this in later.
2359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            outValue->data = 0;
2360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (outStr) {
2363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            *outStr = finalStr;
2364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return true;
2369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiuint32_t ResourceTable::getCustomResource(
2372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16& package, const String16& type, const String16& name) const
2373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getCustomResource: %s %s %s\n", String8(package).string(),
2375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //       String8(type).string(), String8(name).string());
2376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p = mPackages.valueFor(package);
2377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p == NULL) return 0;
2378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = p->getTypes().valueFor(type);
2379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (t == NULL) return 0;
2380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<ConfigList> c =  t->getConfigs().valueFor(name);
23819b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    if (c == NULL) {
23829b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (type != String16("attr")) {
23839b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            return 0;
23849b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
23859b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        t = p->getTypes().valueFor(String16(kAttrPrivateType));
23869b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (t == NULL) return 0;
23879b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        c = t->getConfigs().valueFor(name);
23889b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (c == NULL) return 0;
23899b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
2390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int32_t ei = c->getEntryIndex();
2391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ei < 0) return 0;
2392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return getResId(p, t, ei);
2393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiuint32_t ResourceTable::getCustomResourceWithCreation(
2396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16& package, const String16& type, const String16& name,
2397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const bool createIfNotFound)
2398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t resId = getCustomResource(package, type, name);
2400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (resId != 0 || !createIfNotFound) {
2401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return resId;
2402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2404f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    if (mAssetsPackage != package) {
2405833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        mCurrentXmlPos.error("creating resource for external package %s: %s/%s.",
2406f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski                String8(package).string(), String8(type).string(), String8(name).string());
2407833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        if (package == String16("android")) {
2408833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            mCurrentXmlPos.printf("did you mean to use @+id instead of @+android:id?");
2409833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        }
2410833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        return 0;
2411f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    }
2412f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski
2413f90f2f8dc36e7243b85e0b6a7fd5a590893c827eAdam Lesinski    String16 value("false");
2414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t status = addEntry(mCurrentXmlPos, package, type, name, value, NULL, NULL, true);
2415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (status == NO_ERROR) {
2416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        resId = getResId(package, type, name);
2417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return resId;
2418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return 0;
2420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiuint32_t ResourceTable::getRemappedPackage(uint32_t origPackage) const
2423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return origPackage;
2425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getAttributeType(uint32_t attrID, uint32_t* outType)
2428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getAttributeType #%08x\n", attrID);
2430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
2431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (getItemValue(attrID, ResTable_map::ATTR_TYPE, &value)) {
2432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //printf("getAttributeType #%08x (%s): #%08x\n", attrID,
2433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //       String8(getEntry(attrID)->getName()).string(), value.data);
2434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outType = value.data;
2435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getAttributeMin(uint32_t attrID, uint32_t* outMin)
2441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getAttributeMin #%08x\n", attrID);
2443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
2444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (getItemValue(attrID, ResTable_map::ATTR_MIN, &value)) {
2445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outMin = value.data;
2446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getAttributeMax(uint32_t attrID, uint32_t* outMax)
2452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getAttributeMax #%08x\n", attrID);
2454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
2455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (getItemValue(attrID, ResTable_map::ATTR_MAX, &value)) {
2456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *outMax = value.data;
2457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiuint32_t ResourceTable::getAttributeL10N(uint32_t attrID)
2463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getAttributeL10N #%08x\n", attrID);
2465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value value;
2466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (getItemValue(attrID, ResTable_map::ATTR_L10N, &value)) {
2467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return value.data;
2468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return ResTable_map::L10N_NOT_REQUIRED;
2470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getLocalizationSetting()
2473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return mBundle->getRequireLocalization();
2475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::reportError(void* accessorCookie, const char* fmt, ...)
2478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (accessorCookie != NULL && fmt != NULL) {
2480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AccessorCookie* ac = (AccessorCookie*)accessorCookie;
2481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int retval=0;
2482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        char buf[1024];
2483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        va_list ap;
2484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        va_start(ap, fmt);
2485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        retval = vsnprintf(buf, sizeof(buf), fmt, ap);
2486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        va_end(ap);
2487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n",
2488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            buf, ac->attr.string(), ac->value.string());
2489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getAttributeKeys(
2493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t attrID, Vector<String16>* outKeys)
2494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<const Entry> e = getEntry(attrID);
2496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e != NULL) {
2497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = e->getBag().size();
2498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
2499282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String16& key = e->getBag().keyAt(i);
2500282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (key.size() > 0 && key.string()[0] != '^') {
2501282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                outKeys->add(key);
2502282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2503282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2504282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getAttributeEnum(
2510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t attrID, const char16_t* name, size_t nameLen,
2511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value* outValue)
2512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).string());
2514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 nameStr(name, nameLen);
2515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<const Entry> e = getEntry(attrID);
2516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e != NULL) {
2517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = e->getBag().size();
2518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
2519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //printf("Comparing %s to %s\n", String8(name, nameLen).string(),
2520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //       String8(e->getBag().keyAt(i)).string());
2521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (e->getBag().keyAt(i) == nameStr) {
2522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, outValue);
2523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getAttributeFlags(
2530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t attrID, const char16_t* name, size_t nameLen,
2531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Res_value* outValue)
2532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outValue->dataType = Res_value::TYPE_INT_HEX;
2534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    outValue->data = 0;
2535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).string());
2537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    String16 nameStr(name, nameLen);
2538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<const Entry> e = getEntry(attrID);
2539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e != NULL) {
2540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = e->getBag().size();
2541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char16_t* end = name + nameLen;
2543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char16_t* pos = name;
2544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (pos < end) {
2545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char16_t* start = pos;
2546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (pos < end && *pos != '|') {
2547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                pos++;
2548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 nameStr(start, pos-start);
2551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t i;
2552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (i=0; i<N; i++) {
2553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).string(),
2554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //       String8(e->getBag().keyAt(i)).string());
2555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (e->getBag().keyAt(i) == nameStr) {
2556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Res_value val;
2557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    bool got = getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, &val);
2558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (!got) {
2559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        return false;
2560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    //printf("Got value: 0x%08x\n", val.data);
2562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    outValue->data |= val.data;
2563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
2564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (i >= N) {
2568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Didn't find this flag identifier.
2569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return false;
2570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            pos++;
2572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
2575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
2577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::assignResourceIds()
2580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mOrderedPackages.size();
2582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t pi;
2583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t firstError = NO_ERROR;
2584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // First generate all bag attributes and assign indices.
2586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (pi=0; pi<N; pi++) {
2587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Package> p = mOrderedPackages.itemAt(pi);
2588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (p == NULL || p->getTypes().size() == 0) {
2589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Empty, skip!
2590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
25939b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (mPackageType == System) {
25949b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            p->movePrivateAttrs();
25959b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
25969b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
2597833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        // This has no sense for packages being built as AppFeature (aka with a non-zero offset).
2598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = p->applyPublicTypeOrder();
2599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR && firstError == NO_ERROR) {
2600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            firstError = err;
2601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Generate attributes...
2604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = p->getOrderedTypes().size();
2605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t ti;
2606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (ti=0; ti<N; ti++) {
2607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getOrderedTypes().itemAt(ti);
2608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t == NULL) {
2609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
2610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = t->getOrderedConfigs().size();
2612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t ci=0; ci<N; ci++) {
2613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (c == NULL) {
2615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
2616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const size_t N = c->getEntries().size();
2618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t ei=0; ei<N; ei++) {
2619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<Entry> e = c->getEntries().valueAt(ei);
2620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (e == NULL) {
2621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        continue;
2622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    status_t err = e->generateAttributes(this, p->getName());
2624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err != NO_ERROR && firstError == NO_ERROR) {
2625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        firstError = err;
2626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2631833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        uint32_t typeIdOffset = 0;
2632833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        if (mPackageType == AppFeature && p->getName() == mAssetsPackage) {
2633833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            typeIdOffset = mTypeIdOffset;
2634833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        }
2635833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
2636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const SourcePos unknown(String8("????"), 0);
2637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Type> attr = p->getType(String16("attr"), unknown);
2638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
26394d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski        // Force creation of ID if we are building feature splits.
26404d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski        // Auto-generated ID resources won't apply the type ID offset correctly unless
26414d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski        // the offset is applied here first.
26424d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski        // b/30607637
26434d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski        if (mPackageType == AppFeature && p->getName() == mAssetsPackage) {
26444d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski            sp<Type> id = p->getType(String16("id"), unknown);
26454d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski        }
26464d219da3c43f12ff000e685ae069374b618b30fcAdam Lesinski
2647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Assign indices...
264843a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski        const size_t typeCount = p->getOrderedTypes().size();
264943a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski        for (size_t ti = 0; ti < typeCount; ti++) {
2650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getOrderedTypes().itemAt(ti);
2651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t == NULL) {
2652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
2653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
265443a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski
2655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = t->applyPublicEntryOrder();
2656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (err != NO_ERROR && firstError == NO_ERROR) {
2657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                firstError = err;
2658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = t->getOrderedConfigs().size();
2661833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            t->setIndex(ti + 1 + typeIdOffset);
2662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            LOG_ALWAYS_FATAL_IF(ti == 0 && attr != t,
2664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                "First type is not attr!");
2665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t ei=0; ei<N; ei++) {
2667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ei);
2668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (c == NULL) {
2669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
2670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                c->setEntryIndex(ei);
2672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
26759b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
2676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Assign resource IDs to keys in bags...
267743a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski        for (size_t ti = 0; ti < typeCount; ti++) {
2678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getOrderedTypes().itemAt(ti);
2679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t == NULL) {
2680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
2681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
26829b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
2683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = t->getOrderedConfigs().size();
2684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t ci=0; ci<N; ci++) {
2685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
26869b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                if (c == NULL) {
26879b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    continue;
26889b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                }
2689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                //printf("Ordered config #%d: %p\n", ci, c.get());
2690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const size_t N = c->getEntries().size();
2691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t ei=0; ei<N; ei++) {
2692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<Entry> e = c->getEntries().valueAt(ei);
2693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (e == NULL) {
2694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        continue;
2695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    status_t err = e->assignResourceIds(this, p->getName());
2697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err != NO_ERROR && firstError == NO_ERROR) {
2698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        firstError = err;
2699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return firstError;
2705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
27075892248580859620db90d5ef2e3c2f48531933faAdrian Roosstatus_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols,
27085892248580859620db90d5ef2e3c2f48531933faAdrian Roos        bool skipSymbolsWithoutDefaultLocalization) {
2709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mOrderedPackages.size();
27105892248580859620db90d5ef2e3c2f48531933faAdrian Roos    const String8 defaultLocale;
27115892248580859620db90d5ef2e3c2f48531933faAdrian Roos    const String16 stringType("string");
2712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t pi;
2713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (pi=0; pi<N; pi++) {
2715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Package> p = mOrderedPackages.itemAt(pi);
2716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (p->getTypes().size() == 0) {
2717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Empty, skip!
2718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = p->getOrderedTypes().size();
2722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t ti;
2723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (ti=0; ti<N; ti++) {
2725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getOrderedTypes().itemAt(ti);
2726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t == NULL) {
2727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
2728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
27299b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
2730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = t->getOrderedConfigs().size();
27319b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            sp<AaptSymbols> typeSymbols;
27329b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            if (t->getName() == String16(kAttrPrivateType)) {
27339b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                typeSymbols = outSymbols->addNestedSymbol(String8("attr"), t->getPos());
27349b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            } else {
27359b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
27369b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            }
27379b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
27383fb8c9b50ef1873454acf3a4e7fd33ad182c03d7Adam Lesinski            if (typeSymbols == NULL) {
27393fb8c9b50ef1873454acf3a4e7fd33ad182c03d7Adam Lesinski                return UNKNOWN_ERROR;
27403fb8c9b50ef1873454acf3a4e7fd33ad182c03d7Adam Lesinski            }
27413fb8c9b50ef1873454acf3a4e7fd33ad182c03d7Adam Lesinski
2742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t ci=0; ci<N; ci++) {
2743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (c == NULL) {
2745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
2746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                uint32_t rid = getResId(p, t, ci);
2748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (rid == 0) {
2749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return UNKNOWN_ERROR;
2750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2751833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                if (Res_GETPACKAGE(rid) + 1 == p->getAssignedId()) {
27525892248580859620db90d5ef2e3c2f48531933faAdrian Roos
27535892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    if (skipSymbolsWithoutDefaultLocalization &&
27545892248580859620db90d5ef2e3c2f48531933faAdrian Roos                            t->getName() == stringType) {
27555892248580859620db90d5ef2e3c2f48531933faAdrian Roos
27565892248580859620db90d5ef2e3c2f48531933faAdrian Roos                        // Don't generate symbols for strings without a default localization.
27575892248580859620db90d5ef2e3c2f48531933faAdrian Roos                        if (mHasDefaultLocalization.find(c->getName())
27585892248580859620db90d5ef2e3c2f48531933faAdrian Roos                                == mHasDefaultLocalization.end()) {
27595892248580859620db90d5ef2e3c2f48531933faAdrian Roos                            // printf("Skip symbol [%08x] %s\n", rid,
27605892248580859620db90d5ef2e3c2f48531933faAdrian Roos                            //          String8(c->getName()).string());
27615892248580859620db90d5ef2e3c2f48531933faAdrian Roos                            continue;
27625892248580859620db90d5ef2e3c2f48531933faAdrian Roos                        }
27635892248580859620db90d5ef2e3c2f48531933faAdrian Roos                    }
27645892248580859620db90d5ef2e3c2f48531933faAdrian Roos
2765282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    typeSymbols->addSymbol(String8(c->getName()), rid, c->getPos());
2766282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String16 comment(c->getComment());
2768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    typeSymbols->appendComment(String8(c->getName()), comment, c->getPos());
27698ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                    //printf("Type symbol [%08x] %s comment: %s\n", rid,
27708ff15b4cada7998e78c93934ab2c869c322d7e07Adam Lesinski                    //        String8(c->getName()).string(), String8(comment).string());
2771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    comment = c->getTypeComment();
2772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    typeSymbols->appendTypeComment(String8(c->getName()), comment);
2773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
2778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid
2782a01a9374fd386f3a8773528d7a49bc5315492dffAdam LesinskiResourceTable::addLocalization(const String16& name, const String8& locale, const SourcePos& src)
2783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2784a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski    mLocalizations[name][locale] = src;
2785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
27875892248580859620db90d5ef2e3c2f48531933faAdrian Roosvoid
27885892248580859620db90d5ef2e3c2f48531933faAdrian RoosResourceTable::addDefaultLocalization(const String16& name)
27895892248580859620db90d5ef2e3c2f48531933faAdrian Roos{
27905892248580859620db90d5ef2e3c2f48531933faAdrian Roos    mHasDefaultLocalization.insert(name);
27915892248580859620db90d5ef2e3c2f48531933faAdrian Roos}
27925892248580859620db90d5ef2e3c2f48531933faAdrian Roos
2793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*!
2795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Flag various sorts of localization problems.  '+' indicates checks already implemented;
2796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * '-' indicates checks that will be implemented in the future.
2797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
2798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * + A localized string for which no default-locale version exists => warning
2799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * + A string for which no version in an explicitly-requested locale exists => warning
2800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * + A localized translation of an translateable="false" string => warning
2801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * - A localized string not provided in every locale used by the table
2802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
2803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t
2804282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiResourceTable::validateLocalizations(void)
2805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = NO_ERROR;
2807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String8 defaultLocale;
2808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // For all strings...
2810030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert    for (const auto& nameIter : mLocalizations) {
2811030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert        const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
2812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Look for strings with no default localization
2814a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski        if (configSrcMap.count(defaultLocale) == 0) {
2815a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski            SourcePos().warning("string '%s' has no default translation.",
2816030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert                    String8(nameIter.first).string());
2817a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski            if (mBundle->getVerbose()) {
2818030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert                for (const auto& locale : configSrcMap) {
2819030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert                    locale.second.printf("locale %s found", locale.first.string());
2820a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                }
2821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // !!! TODO: throw an error here in some circumstances
2823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Check that all requested localizations are present for this string
2826fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski        if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
2827fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski            const char* allConfigs = mBundle->getConfigurations().string();
2828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* start = allConfigs;
2829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const char* comma;
2830030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert
2831030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert            std::set<String8> missingConfigs;
2832a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski            AaptLocaleValue locale;
2833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            do {
2834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8 config;
2835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                comma = strchr(start, ',');
2836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (comma != NULL) {
2837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.setTo(start, comma - start);
2838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    start = comma + 1;
2839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
2840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.setTo(start);
2841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2843a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                if (!locale.initFromFilterString(config)) {
2844a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                    continue;
2845a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                }
2846a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski
2847a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                // don't bother with the pseudolocale "en_XA" or "ar_XB"
2848a2ef5c0d4fb863c0382e77ae00f986a019b11cbeAnton Krumin                if (config != "en_XA" && config != "ar_XB") {
2849a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                    if (configSrcMap.find(config) == configSrcMap.end()) {
2850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // okay, no specific localization found.  it's possible that we are
2851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // requiring a specific regional localization [e.g. de_DE] but there is an
2852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // available string in the generic language localization [e.g. de];
2853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // consider that string to have fulfilled the localization requirement.
2854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8 region(config.string(), 2);
2855a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                        if (configSrcMap.find(region) == configSrcMap.end() &&
2856a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                                configSrcMap.count(defaultLocale) == 0) {
2857a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                            missingConfigs.insert(config);
2858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
2859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2861a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski            } while (comma != NULL);
2862a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski
2863a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski            if (!missingConfigs.empty()) {
2864a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                String8 configStr;
2865030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert                for (const auto& iter : missingConfigs) {
2866030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert                    configStr.appendFormat(" %s", iter.string());
2867a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                }
2868a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                SourcePos().warning("string '%s' is missing %u required localizations:%s",
2869030f536009b56dbcc23d284541e51562bd9a6ed3Dan Albert                        String8(nameIter.first).string(),
2870a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                        (unsigned int)missingConfigs.size(),
2871a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski                        configStr.string());
2872a01a9374fd386f3a8773528d7a49bc5315492dffAdam Lesinski            }
2873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
2877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
2878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
287927f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinskistatus_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
288027f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski        const sp<AaptFile>& dest,
288127f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski        const bool isBase)
2882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
2883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const ConfigDescription nullConfig;
2884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mOrderedPackages.size();
2886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t pi;
2887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const static String16 mipmap16("mipmap");
2889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool useUTF8 = !bundle->getUTF16StringsOption();
2891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2892de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    // The libraries this table references.
2893de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    Vector<sp<Package> > libraryPackages;
28946022debdbcc4498736580640c6287b57872617a2Adam Lesinski    const ResTable& table = mAssets->getIncludedResources();
28956022debdbcc4498736580640c6287b57872617a2Adam Lesinski    const size_t basePackageCount = table.getBasePackageCount();
28966022debdbcc4498736580640c6287b57872617a2Adam Lesinski    for (size_t i = 0; i < basePackageCount; i++) {
28976022debdbcc4498736580640c6287b57872617a2Adam Lesinski        size_t packageId = table.getBasePackageId(i);
28986022debdbcc4498736580640c6287b57872617a2Adam Lesinski        String16 packageName(table.getBasePackageName(i));
28996022debdbcc4498736580640c6287b57872617a2Adam Lesinski        if (packageId > 0x01 && packageId != 0x7f &&
29006022debdbcc4498736580640c6287b57872617a2Adam Lesinski                packageName != String16("android")) {
29016022debdbcc4498736580640c6287b57872617a2Adam Lesinski            libraryPackages.add(sp<Package>(new Package(packageName, packageId)));
29026022debdbcc4498736580640c6287b57872617a2Adam Lesinski        }
29036022debdbcc4498736580640c6287b57872617a2Adam Lesinski    }
2904de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
2905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Iterate through all data, collecting all values (strings,
2906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // references, etc).
2907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    StringPool valueStrings(useUTF8);
2908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<sp<Entry> > allEntries;
2909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (pi=0; pi<N; pi++) {
2910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Package> p = mOrderedPackages.itemAt(pi);
2911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (p->getTypes().size() == 0) {
2912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
2913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        StringPool typeStrings(useUTF8);
2916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        StringPool keyStrings(useUTF8);
2917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2918833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        ssize_t stringsAdded = 0;
2919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = p->getOrderedTypes().size();
2920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t ti=0; ti<N; ti++) {
2921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getOrderedTypes().itemAt(ti);
2922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t == NULL) {
2923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                typeStrings.add(String16("<empty>"), false);
2924833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                stringsAdded++;
2925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
2926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2927833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
2928833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            while (stringsAdded < t->getIndex() - 1) {
2929833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                typeStrings.add(String16("<empty>"), false);
2930833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                stringsAdded++;
2931833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            }
2932833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski
2933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String16 typeName(t->getName());
2934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            typeStrings.add(typeName, false);
2935833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            stringsAdded++;
2936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This is a hack to tweak the sorting order of the final strings,
2938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // to put stuff that is generally not language-specific first.
2939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String8 configTypeName(typeName);
2940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (configTypeName == "drawable" || configTypeName == "layout"
2941282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    || configTypeName == "color" || configTypeName == "anim"
2942282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    || configTypeName == "interpolator" || configTypeName == "animator"
2943282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    || configTypeName == "xml" || configTypeName == "menu"
2944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    || configTypeName == "mipmap" || configTypeName == "raw") {
2945282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                configTypeName = "1complex";
2946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
2947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                configTypeName = "2value";
2948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
295027f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            // mipmaps don't get filtered, so they will
295127f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            // allways end up in the base. Make sure they
295227f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            // don't end up in a split.
295327f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            if (typeName == mipmap16 && !isBase) {
295427f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                continue;
295527f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            }
295627f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski
2957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const bool filterable = (typeName != mipmap16);
2958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = t->getOrderedConfigs().size();
2960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t ci=0; ci<N; ci++) {
2961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (c == NULL) {
2963282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
2964282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2965282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const size_t N = c->getEntries().size();
2966282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t ei=0; ei<N; ei++) {
2967282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ConfigDescription config = c->getEntries().keyAt(ei);
2968fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                    if (filterable && !filter->match(config)) {
2969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        continue;
2970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<Entry> e = c->getEntries().valueAt(ei);
2972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (e == NULL) {
2973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        continue;
2974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    e->setNameIndex(keyStrings.add(e->getName(), true));
2976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // If this entry has no values for other configs,
2978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // and is the default config, then it is special.  Otherwise
2979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // we want to add it with the config info.
2980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    ConfigDescription* valueConfig = NULL;
2981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (N != 1 || config == nullConfig) {
2982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        valueConfig = &config;
2983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    status_t err = e->prepareFlatten(&valueStrings, this,
2986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            &configTypeName, &config);
2987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (err != NO_ERROR) {
2988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        return err;
2989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
2990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    allEntries.add(e);
2991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
2992282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
2993282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
2994282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2995282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        p->setTypeStrings(typeStrings.createStringBlock());
2996282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        p->setKeyStrings(keyStrings.createStringBlock());
2997282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
2998282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2999282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (bundle->getOutputAPKFile() != NULL) {
3000282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Now we want to sort the value strings for better locality.  This will
3001282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // cause the positions of the strings to change, so we need to go back
3002282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // through out resource entries and update them accordingly.  Only need
3003282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // to do this if actually writing the output file.
3004282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        valueStrings.sortByConfig();
3005282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (pi=0; pi<allEntries.size(); pi++) {
3006282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            allEntries[pi]->remapStringValue(&valueStrings);
3007282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3008282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3009282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3010282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t strAmt = 0;
3011de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3012282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Now build the array of package chunks.
3013282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<sp<AaptFile> > flatPackages;
3014282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (pi=0; pi<N; pi++) {
3015282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Package> p = mOrderedPackages.itemAt(pi);
3016282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (p->getTypes().size() == 0) {
3017282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Empty, skip!
3018282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            continue;
3019282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3020282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3021282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = p->getTypeStrings().size();
3022282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3023282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t baseSize = sizeof(ResTable_package);
3024282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3025282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Start the package data.
3026282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
3027282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResTable_package* header = (ResTable_package*)data->editData(baseSize);
3028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (header == NULL) {
3029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: out of memory creating ResTable_package\n");
3030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NO_MEMORY;
3031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memset(header, 0, sizeof(*header));
3033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->header.type = htods(RES_TABLE_PACKAGE_TYPE);
3034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->header.headerSize = htods(sizeof(*header));
3035833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        header->id = htodl(static_cast<uint32_t>(p->getAssignedId()));
3036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strcpy16_htod(header->name, p->getName().string());
3037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Write the string blocks.
3039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t typeStringsStart = data->getSize();
3040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<AaptFile> strFile = p->getTypeStringsData();
3041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ssize_t amt = data->writeData(strFile->getData(), strFile->getSize());
30422412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kPrintStringMetrics) {
30432412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            fprintf(stderr, "**** type strings: %zd\n", SSIZE(amt));
30442412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        }
3045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strAmt += amt;
3046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (amt < 0) {
3047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return amt;
3048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t keyStringsStart = data->getSize();
3050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strFile = p->getKeyStringsData();
3051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        amt = data->writeData(strFile->getData(), strFile->getSize());
30522412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kPrintStringMetrics) {
30532412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            fprintf(stderr, "**** key strings: %zd\n", SSIZE(amt));
30542412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        }
3055282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        strAmt += amt;
3056282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (amt < 0) {
3057282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return amt;
3058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
306027f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski        if (isBase) {
306127f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            status_t err = flattenLibraryTable(data, libraryPackages);
306227f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            if (err != NO_ERROR) {
306327f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                fprintf(stderr, "ERROR: failed to write library table\n");
306427f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                return err;
306527f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            }
3066de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        }
3067de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Build the type chunks inside of this package.
3069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t ti=0; ti<N; ti++) {
3070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Retrieve them in the same order as the type string block.
3071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
3072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String16 typeName(p->getTypeStrings().stringAt(ti, &len));
3073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = p->getTypes().valueFor(typeName);
3074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"),
3075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                "Type name %s not found",
3076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String8(typeName).string());
3077833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            if (t == NULL) {
3078833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                continue;
3079833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            }
3080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const bool filterable = (typeName != mipmap16);
308127f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            const bool skipEntireType = (typeName == mipmap16 && !isBase);
3082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
3084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Until a non-NO_ENTRY value has been written for a resource,
3086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // that resource is invalid; validResources[i] represents
3087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // the item at t->getOrderedConfigs().itemAt(i).
3088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Vector<bool> validResources;
3089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            validResources.insertAt(false, 0, N);
3090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // First write the typeSpec chunk, containing information about
3092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // each resource entry in this type.
3093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            {
3094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const size_t typeSpecSize = sizeof(ResTable_typeSpec) + sizeof(uint32_t)*N;
3095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const size_t typeSpecStart = data->getSize();
3096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ResTable_typeSpec* tsHeader = (ResTable_typeSpec*)
3097282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (((uint8_t*)data->editData(typeSpecStart+typeSpecSize)) + typeSpecStart);
3098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (tsHeader == NULL) {
3099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    fprintf(stderr, "ERROR: out of memory creating ResTable_typeSpec\n");
3100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return NO_MEMORY;
3101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                memset(tsHeader, 0, sizeof(*tsHeader));
3103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tsHeader->header.type = htods(RES_TABLE_TYPE_SPEC_TYPE);
3104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tsHeader->header.headerSize = htods(sizeof(*tsHeader));
3105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tsHeader->header.size = htodl(typeSpecSize);
3106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tsHeader->id = ti+1;
3107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tsHeader->entryCount = htodl(N);
3108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                uint32_t* typeSpecFlags = (uint32_t*)
3110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (((uint8_t*)data->editData())
3111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        + typeSpecStart + sizeof(ResTable_typeSpec));
3112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                memset(typeSpecFlags, 0, sizeof(uint32_t)*N);
3113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t ei=0; ei<N; ei++) {
3115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
31169b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    if (cl == NULL) {
31179b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                        continue;
31189b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    }
31199b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
3120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (cl->getPublic()) {
3121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
3122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
312327f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski
312427f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                    if (skipEntireType) {
312527f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                        continue;
312627f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                    }
312727f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski
3128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    const size_t CN = cl->getEntries().size();
3129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t ci=0; ci<CN; ci++) {
3130fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                        if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
3131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            continue;
3132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
3133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        for (size_t cj=ci+1; cj<CN; cj++) {
3134fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                            if (filterable && !filter->match(cl->getEntries().keyAt(cj))) {
3135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                continue;
3136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            }
3137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            typeSpecFlags[ei] |= htodl(
3138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                cl->getEntries().keyAt(ci).diff(cl->getEntries().keyAt(cj)));
3139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
3140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
3141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
314427f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            if (skipEntireType) {
314527f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski                continue;
314627f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski            }
314727f69f4e06961fdecd1078b2292d764a157e5e1cAdam Lesinski
3148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // We need to write one type chunk for each configuration for
3149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // which we have entries in this type.
3150e97908d32ee8ea80138d085260a0eac93841c722Adam Lesinski            SortedVector<ConfigDescription> uniqueConfigs;
3151e97908d32ee8ea80138d085260a0eac93841c722Adam Lesinski            if (t != NULL) {
3152e97908d32ee8ea80138d085260a0eac93841c722Adam Lesinski                uniqueConfigs = t->getUniqueConfigs();
3153e97908d32ee8ea80138d085260a0eac93841c722Adam Lesinski            }
3154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N;
3156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3157e97908d32ee8ea80138d085260a0eac93841c722Adam Lesinski            const size_t NC = uniqueConfigs.size();
3158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t ci=0; ci<NC; ci++) {
31599b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                const ConfigDescription& config = uniqueConfigs[ci];
3160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
31612412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                if (kIsDebug) {
31622412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    printf("Writing config %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
31632412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
31642412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        "sw%ddp w%ddp h%ddp layout:%d\n",
31652412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        ti + 1,
31662412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.mcc, config.mnc,
31672412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.language[0] ? config.language[0] : '-',
31682412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.language[1] ? config.language[1] : '-',
31692412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.country[0] ? config.country[0] : '-',
31702412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.country[1] ? config.country[1] : '-',
31712412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.orientation,
31722412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.uiMode,
31732412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.touchscreen,
31742412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.density,
31752412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.keyboard,
31762412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.inputFlags,
31772412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.navigation,
31782412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.screenWidth,
31792412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.screenHeight,
31802412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.smallestScreenWidthDp,
31812412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.screenWidthDp,
31822412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.screenHeightDp,
31832412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        config.screenLayout);
31842412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                }
3185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3186fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski                if (filterable && !filter->match(config)) {
3187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
3188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                const size_t typeStart = data->getSize();
3191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ResTable_type* tHeader = (ResTable_type*)
3193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (((uint8_t*)data->editData(typeStart+typeSize)) + typeStart);
3194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (tHeader == NULL) {
3195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    fprintf(stderr, "ERROR: out of memory creating ResTable_type\n");
3196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return NO_MEMORY;
3197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                memset(tHeader, 0, sizeof(*tHeader));
3200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->header.type = htods(RES_TABLE_TYPE_TYPE);
3201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->header.headerSize = htods(sizeof(*tHeader));
3202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->id = ti+1;
3203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->entryCount = htodl(N);
3204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->entriesStart = htodl(typeSize);
3205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->config = config;
32062412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                if (kIsDebug) {
32072412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    printf("Writing type %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
32082412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
32092412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        "sw%ddp w%ddp h%ddp layout:%d\n",
32102412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        ti + 1,
32112412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.mcc, tHeader->config.mnc,
32122412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.language[0] ? tHeader->config.language[0] : '-',
32132412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.language[1] ? tHeader->config.language[1] : '-',
32142412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.country[0] ? tHeader->config.country[0] : '-',
32152412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.country[1] ? tHeader->config.country[1] : '-',
32162412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.orientation,
32172412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.uiMode,
32182412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.touchscreen,
32192412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.density,
32202412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.keyboard,
32212412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.inputFlags,
32222412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.navigation,
32232412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.screenWidth,
32242412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.screenHeight,
32252412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.smallestScreenWidthDp,
32262412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.screenWidthDp,
32272412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.screenHeightDp,
32282412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        tHeader->config.screenLayout);
32292412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                }
3230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->config.swapHtoD();
3231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Build the entries inside of this type.
3233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (size_t ei=0; ei<N; ei++) {
3234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
32359b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    sp<Entry> e = NULL;
32369b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    if (cl != NULL) {
32379b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                        e = cl->getEntries().valueFor(config);
32389b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    }
3239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // Set the offset for this entry in its type.
3241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    uint32_t* index = (uint32_t*)
3242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        (((uint8_t*)data->editData())
3243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            + typeStart + sizeof(ResTable_type));
3244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (e != NULL) {
3245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        index[ei] = htodl(data->getSize()-typeStart-typeSize);
3246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // Create the entry.
3248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ssize_t amt = e->flatten(bundle, data, cl->getPublic());
3249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (amt < 0) {
3250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            return amt;
3251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
3252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        validResources.editItemAt(ei) = true;
3253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
3254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        index[ei] = htodl(ResTable_type::NO_ENTRY);
3255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
3256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Fill in the rest of the type information.
3259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader = (ResTable_type*)
3260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    (((uint8_t*)data->editData()) + typeStart);
3261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                tHeader->header.size = htodl(data->getSize()-typeStart);
3262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3264833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            // If we're building splits, then each invocation of the flattening
3265833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            // step will have 'missing' entries. Don't warn/error for this case.
3266833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski            if (bundle->getSplitConfigurations().isEmpty()) {
3267833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                bool missing_entry = false;
3268833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                const char* log_prefix = bundle->getErrorOnMissingConfigEntry() ?
3269833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                        "error" : "warning";
3270833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                for (size_t i = 0; i < N; ++i) {
3271833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                    if (!validResources[i]) {
3272833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                        sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
32739b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                        if (c != NULL) {
327401f185633c1c12017731336e7f926fe398c69781Colin Cross                            fprintf(stderr, "%s: no entries written for %s/%s (0x%08zx)\n", log_prefix,
32759b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                                    String8(typeName).string(), String8(c->getName()).string(),
32769b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                                    Res_MAKEID(p->getAssignedId() - 1, ti, i));
32779b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                        }
3278833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                        missing_entry = true;
3279833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                    }
3280833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                }
3281833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                if (bundle->getErrorOnMissingConfigEntry() && missing_entry) {
3282833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                    fprintf(stderr, "Error: Missing entries, quit!\n");
3283833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski                    return NOT_ENOUGH_DATA;
3284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3285cd28bd37ea2d88dd72930f032ca73daaad5744b4Ying Wang            }
3286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Fill in the rest of the package information.
3289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header = (ResTable_package*)data->editData();
3290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->header.size = htodl(data->getSize());
3291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->typeStrings = htodl(typeStringsStart);
3292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->lastPublicType = htodl(p->getTypeStrings().size());
3293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->keyStrings = htodl(keyStringsStart);
3294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header->lastPublicKey = htodl(p->getKeyStrings().size());
3295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        flatPackages.add(data);
3297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // And now write out the final chunks.
3300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t dataStart = dest->getSize();
3301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
3303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // blah
3304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResTable_header header;
3305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memset(&header, 0, sizeof(header));
3306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header.header.type = htods(RES_TABLE_TYPE);
3307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header.header.headerSize = htods(sizeof(header));
3308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        header.packageCount = htodl(flatPackages.size());
3309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = dest->writeData(&header, sizeof(header));
3310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
3311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: out of memory creating ResTable_header\n");
3312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
3313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t strStart = dest->getSize();
3317fab50875b98e8274ac8ee44b38ba42521bbbf1f9Adam Lesinski    status_t err = valueStrings.writeStringBlock(dest);
3318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
3319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
3320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t amt = (dest->getSize()-strStart);
3323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    strAmt += amt;
33242412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kPrintStringMetrics) {
33252412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        fprintf(stderr, "**** value strings: %zd\n", SSIZE(amt));
33262412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        fprintf(stderr, "**** total strings: %zd\n", SSIZE(strAmt));
33272412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
3328de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (pi=0; pi<flatPackages.size(); pi++) {
3330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = dest->writeData(flatPackages[pi]->getData(),
3331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                              flatPackages[pi]->getSize());
3332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
3333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: out of memory creating package chunk for ResTable_header\n");
3334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
3335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_header* header = (ResTable_header*)
3339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        (((uint8_t*)dest->getData()) + dataStart);
3340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header->header.size = htodl(dest->getSize() - dataStart);
3341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33422412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (kPrintStringMetrics) {
33432412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        fprintf(stderr, "**** total resource table size: %zu / %zu%% strings\n",
33442412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                dest->getSize(), (size_t)(strAmt*100)/dest->getSize());
33452412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
3346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3350de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinskistatus_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs) {
3351de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    // Write out the library table if necessary
3352de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    if (libs.size() > 0) {
335387332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe        if (kIsDebug) {
335487332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe            fprintf(stderr, "Writing library reference table\n");
335587332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe        }
3356de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3357de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        const size_t libStart = dest->getSize();
3358de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        const size_t count = libs.size();
33596022debdbcc4498736580640c6287b57872617a2Adam Lesinski        ResTable_lib_header* libHeader = (ResTable_lib_header*) dest->editDataInRange(
33606022debdbcc4498736580640c6287b57872617a2Adam Lesinski                libStart, sizeof(ResTable_lib_header));
3361de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3362de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        memset(libHeader, 0, sizeof(*libHeader));
3363de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        libHeader->header.type = htods(RES_TABLE_LIBRARY_TYPE);
3364de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        libHeader->header.headerSize = htods(sizeof(*libHeader));
3365de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        libHeader->header.size = htodl(sizeof(*libHeader) + (sizeof(ResTable_lib_entry) * count));
3366de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        libHeader->count = htodl(count);
3367de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3368de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        // Write the library entries
3369de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        for (size_t i = 0; i < count; i++) {
3370de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            const size_t entryStart = dest->getSize();
3371de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            sp<Package> libPackage = libs[i];
337287332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe            if (kIsDebug) {
337387332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                fprintf(stderr, "  Entry %s -> 0x%02x\n",
3374de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski                        String8(libPackage->getName()).string(),
337587332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                        (uint8_t)libPackage->getAssignedId());
337687332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe            }
3377de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
33786022debdbcc4498736580640c6287b57872617a2Adam Lesinski            ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(
33796022debdbcc4498736580640c6287b57872617a2Adam Lesinski                    entryStart, sizeof(ResTable_lib_entry));
3380de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            memset(entry, 0, sizeof(*entry));
3381de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            entry->packageId = htodl(libPackage->getAssignedId());
3382de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski            strcpy16_htod(entry->packageName, libPackage->getName().string());
3383de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        }
3384de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    }
3385de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski    return NO_ERROR;
3386de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski}
3387de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski
3388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::writePublicDefinitions(const String16& package, FILE* fp)
3389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(fp,
3391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    "<!-- This file contains <public> resource definitions for all\n"
3392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    "     resources that were generated from the source data. -->\n"
3393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    "\n"
3394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    "<resources>\n");
3395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    writePublicDefinitions(package, fp, true);
3397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    writePublicDefinitions(package, fp, false);
3398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(fp,
3400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    "\n"
3401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    "</resources>\n");
3402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::writePublicDefinitions(const String16& package, FILE* fp, bool pub)
3405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool didHeader = false;
3407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> pkg = mPackages.valueFor(package);
3409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (pkg != NULL) {
3410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t NT = pkg->getOrderedTypes().size();
3411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<NT; i++) {
3412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<Type> t = pkg->getOrderedTypes().itemAt(i);
3413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (t == NULL) {
3414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                continue;
3415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            bool didType = false;
3418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t NC = t->getOrderedConfigs().size();
3420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (size_t j=0; j<NC; j++) {
3421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(j);
3422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (c == NULL) {
3423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
3424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (c->getPublic() != pub) {
3427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    continue;
3428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!didType) {
3431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    fprintf(fp, "\n");
3432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    didType = true;
3433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!didHeader) {
3435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (pub) {
3436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(fp,"  <!-- PUBLIC SECTION.  These resources have been declared public.\n");
3437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(fp,"       Changes to these definitions will break binary compatibility. -->\n\n");
3438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
3439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(fp,"  <!-- PRIVATE SECTION.  These resources have not been declared public.\n");
3440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        fprintf(fp,"       You can make them public my moving these lines into a file in res/values. -->\n\n");
3441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
3442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    didHeader = true;
3443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!pub) {
3445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    const size_t NE = c->getEntries().size();
3446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    for (size_t k=0; k<NE; k++) {
3447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        const SourcePos& pos = c->getEntries().valueAt(k)->getPos();
3448282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        if (pos.file != "") {
3449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            fprintf(fp,"  <!-- Declared at %s:%d -->\n",
3450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                    pos.file.string(), pos.line);
3451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        }
3452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
3453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(fp, "  <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n",
3455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(t->getName()).string(),
3456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(c->getName()).string(),
3457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        getResId(pkg, t, c->getEntryIndex()));
3458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3463282e181b58cf72b6ca770dc7ca5f91f135444502Adam LesinskiResourceTable::Item::Item(const SourcePos& _sourcePos,
3464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                          bool _isId,
3465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                          const String16& _value,
3466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                          const Vector<StringPool::entry_style_span>* _style,
3467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                          int32_t _format)
3468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    : sourcePos(_sourcePos)
3469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    , isId(_isId)
3470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    , value(_value)
3471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    , format(_format)
3472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    , bagKeyId(0)
3473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    , evaluating(false)
3474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (_style) {
3476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        style = *_style;
3477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
348082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam LesinskiResourceTable::Entry::Entry(const Entry& entry)
348182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    : RefBase()
348282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mName(entry.mName)
348382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mParent(entry.mParent)
348482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mType(entry.mType)
348582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mItem(entry.mItem)
348682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mItemFormat(entry.mItemFormat)
348782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mBag(entry.mBag)
348882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mNameIndex(entry.mNameIndex)
348982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mParentId(entry.mParentId)
349082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    , mPos(entry.mPos) {}
349182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
3492978ab9d92934b79409638cf220de3002fea8d505Adam LesinskiResourceTable::Entry& ResourceTable::Entry::operator=(const Entry& entry) {
3493978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mName = entry.mName;
3494978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mParent = entry.mParent;
3495978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mType = entry.mType;
3496978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mItem = entry.mItem;
3497978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mItemFormat = entry.mItemFormat;
3498978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mBag = entry.mBag;
3499978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mNameIndex = entry.mNameIndex;
3500978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mParentId = entry.mParentId;
3501978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    mPos = entry.mPos;
3502978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski    return *this;
3503978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski}
3504978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski
3505282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos)
3506282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3507282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mType == TYPE_BAG) {
3508282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_ERROR;
3509282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3510282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mType == TYPE_UNKNOWN) {
3511282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mType = TYPE_BAG;
3512282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NO_ERROR;
3513282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3514282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sourcePos.error("Resource entry %s is already defined as a single item.\n"
3515282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    "%s:%d: Originally defined here.\n",
3516282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(mName).string(),
3517282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    mItem.sourcePos.file.string(), mItem.sourcePos.line);
3518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return UNKNOWN_ERROR;
3519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::setItem(const SourcePos& sourcePos,
3522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       const String16& value,
3523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       const Vector<StringPool::entry_style_span>* style,
3524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       int32_t format,
3525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                       const bool overwrite)
3526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Item item(sourcePos, false, value, style);
3528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mType == TYPE_BAG) {
353043a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski        if (mBag.size() == 0) {
353143a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski            sourcePos.error("Resource entry %s is already defined as a bag.",
353243a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski                    String8(mName).string());
353343a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski        } else {
353443a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski            const Item& item(mBag.valueAt(0));
353543a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski            sourcePos.error("Resource entry %s is already defined as a bag.\n"
353643a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski                            "%s:%d: Originally defined here.\n",
353743a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski                            String8(mName).string(),
353843a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski                            item.sourcePos.file.string(), item.sourcePos.line);
353943a0df04b0826ffb9e4589aac73b07b0c98abe8cAdam Lesinski        }
3540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
3541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) {
3543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sourcePos.error("Resource entry %s is already defined.\n"
3544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "%s:%d: Originally defined here.\n",
3545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(mName).string(),
3546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        mItem.sourcePos.file.string(), mItem.sourcePos.line);
3547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
3548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mType = TYPE_ITEM;
3551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mItem = item;
3552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mItemFormat = format;
3553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::addToBag(const SourcePos& sourcePos,
3557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        const String16& key, const String16& value,
3558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        const Vector<StringPool::entry_style_span>* style,
3559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        bool replace, bool isId, int32_t format)
3560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = makeItABag(sourcePos);
3562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
3563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
3564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Item item(sourcePos, isId, value, style, format);
3567282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // XXX NOTE: there is an error if you try to have a bag with two keys,
3569282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // one an attr and one an id, with the same name.  Not something we
3570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // currently ever have to worry about.
3571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ssize_t origKey = mBag.indexOfKey(key);
3572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (origKey >= 0) {
3573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!replace) {
3574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const Item& item(mBag.valueAt(origKey));
3575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sourcePos.error("Resource entry %s already has bag item %s.\n"
3576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    "%s:%d: Originally defined here.\n",
3577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(mName).string(), String8(key).string(),
3578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    item.sourcePos.file.string(), item.sourcePos.line);
3579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
3580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //printf("Replacing %s with %s\n",
3582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //       String8(mBag.valueFor(key).value).string(), String8(value).string());
3583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mBag.replaceValueFor(key, item);
3584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mBag.add(key, item);
3587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3588282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
359082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinskistatus_t ResourceTable::Entry::removeFromBag(const String16& key) {
359182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    if (mType != Entry::TYPE_BAG) {
359282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        return NO_ERROR;
359382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    }
359482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
359582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    if (mBag.removeItem(key) >= 0) {
359682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        return NO_ERROR;
359782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    }
359882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    return UNKNOWN_ERROR;
359982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski}
360082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
3601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::emptyBag(const SourcePos& sourcePos)
3602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = makeItABag(sourcePos);
3604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
3605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return err;
3606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mBag.clear();
3609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::generateAttributes(ResourceTable* table,
3613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                  const String16& package)
3614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 attr16("attr");
3616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const String16 id16("id");
3617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mBag.size();
3618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
3619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16& key = mBag.keyAt(i);
3620282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const Item& it = mBag.valueAt(i);
3621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (it.isId) {
3622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!table->hasBagOrEntry(key, &id16, &package)) {
3623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String16 value("false");
362487332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                if (kIsDebug) {
362587332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                    fprintf(stderr, "Generating %s:id/%s\n",
362687332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                            String8(package).string(),
362787332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                            String8(key).string());
362887332a7109610d02ac7f5db6af99d3a11813d5c1Andreas Gampe                }
3629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
3630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                               id16, key, value);
3631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (err != NO_ERROR) {
3632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return err;
3633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (!table->hasBagOrEntry(key, &attr16, &package)) {
3636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#if 1
3638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//             fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n",
3639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//                     String8(key).string());
3640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//             const Item& item(mBag.valueAt(i));
3641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//             fprintf(stderr, "Referenced from file %s line %d\n",
3642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//                     item.sourcePos.file.string(), item.sourcePos.line);
3643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski//             return UNKNOWN_ERROR;
3644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#else
3645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char numberStr[16];
3646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sprintf(numberStr, "%d", ResTable_map::TYPE_ANY);
3647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            status_t err = table->addBag(SourcePos("<generated>", 0), package,
3648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                         attr16, key, String16(""),
3649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                         String16("^type"),
3650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                         String16(numberStr), NULL, NULL);
3651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (err != NO_ERROR) {
3652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return err;
3653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#endif
3655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
36612412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                                                 const String16& /* package */)
3662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool hasErrors = false;
3664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mType == TYPE_BAG) {
3666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* errorMsg;
3667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16 style16("style");
3668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16 attr16("attr");
3669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16 id16("id");
3670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mParentId = 0;
3671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mParent.size() > 0) {
3672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mParentId = table->getResId(mParent, &style16, NULL, &errorMsg);
3673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (mParentId == 0) {
3674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                mPos.error("Error retrieving parent for item: %s '%s'.\n",
3675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        errorMsg, String8(mParent).string());
3676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                hasErrors = true;
3677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = mBag.size();
3680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
3681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String16& key = mBag.keyAt(i);
3682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Item& it = mBag.editValueAt(i);
3683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            it.bagKeyId = table->getResId(key,
3684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    it.isId ? &id16 : &attr16, NULL, &errorMsg);
3685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //printf("Bag key of %s: #%08x\n", String8(key).string(), it.bagKeyId);
3686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (it.bagKeyId == 0) {
3687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                it.sourcePos.error("Error: %s: %s '%s'.\n", errorMsg,
3688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(it.isId ? id16 : attr16).string(),
3689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(key).string());
3690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                hasErrors = true;
3691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
36942412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
3695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
3698282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String8* configTypeName, const ConfigDescription* config)
3699282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mType == TYPE_ITEM) {
3701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Item& it = mItem;
3702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value));
3703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!table->stringToValue(&it.parsedValue, strings,
3704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  it.value, false, true, 0,
3705282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  &it.style, NULL, &ac, mItemFormat,
3706282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                  configTypeName, config)) {
3707282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
3708282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3709282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (mType == TYPE_BAG) {
3710282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = mBag.size();
3711282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
3712282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const String16& key = mBag.keyAt(i);
3713282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Item& it = mBag.editValueAt(i);
3714282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AccessorCookie ac(it.sourcePos, String8(key), String8(it.value));
3715282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!table->stringToValue(&it.parsedValue, strings,
3716282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                      it.value, false, true, it.bagKeyId,
3717282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                      &it.style, NULL, &ac, it.format,
3718282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                      configTypeName, config)) {
3719282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
3720282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3721282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3722282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3723282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mPos.error("Error: entry %s is not a single item or a bag.\n",
3724282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                   String8(mName).string());
3725282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
3726282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3727282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3728282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3729282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3730282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Entry::remapStringValue(StringPool* strings)
3731282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3732282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mType == TYPE_ITEM) {
3733282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Item& it = mItem;
3734282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
3735282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
3736282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3737282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (mType == TYPE_BAG) {
3738282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = mBag.size();
3739282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
3740282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Item& it = mBag.editValueAt(i);
3741282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
3742282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
3743282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3744282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3745282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3746282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mPos.error("Error: entry %s is not a single item or a bag.\n",
3747282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                   String8(mName).string());
3748282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
3749282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3750282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3751282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3752282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
37532412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampessize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp<AaptFile>& data, bool isPublic)
3754282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3755282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t amt = 0;
3756282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ResTable_entry header;
3757282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    memset(&header, 0, sizeof(header));
3758282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    header.size = htods(sizeof(header));
37592412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    const type ty = mType;
37602412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (ty == TYPE_BAG) {
37612412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        header.flags |= htods(header.FLAG_COMPLEX);
3762282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
37632412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    if (isPublic) {
37642412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        header.flags |= htods(header.FLAG_PUBLIC);
37652412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    }
37662412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    header.key.index = htodl(mNameIndex);
3767282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (ty != TYPE_BAG) {
3768282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = data->writeData(&header, sizeof(header));
3769282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
3770282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n");
3771282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
3772282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3773282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3774282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const Item& it = mItem;
3775282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Res_value par;
3776282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memset(&par, 0, sizeof(par));
3777282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        par.size = htods(it.parsedValue.size);
3778282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        par.dataType = it.parsedValue.dataType;
3779282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        par.res0 = it.parsedValue.res0;
3780282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        par.data = htodl(it.parsedValue.data);
3781282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        #if 0
3782282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n",
3783282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski               String8(mName).string(), it.parsedValue.dataType,
3784282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski               it.parsedValue.data, par.res0);
3785282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        #endif
3786282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        err = data->writeData(&par, it.parsedValue.size);
3787282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
3788282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: out of memory creating Res_value\n");
3789282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
3790282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3791282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        amt += it.parsedValue.size;
3792282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3793282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t N = mBag.size();
3794282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        size_t i;
3795282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Create correct ordering of items.
3796282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        KeyedVector<uint32_t, const Item*> items;
3797282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (i=0; i<N; i++) {
3798282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const Item& it = mBag.valueAt(i);
3799282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            items.add(it.bagKeyId, &it);
3800282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3801282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        N = items.size();
3802282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3803282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ResTable_map_entry mapHeader;
3804282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memcpy(&mapHeader, &header, sizeof(header));
3805282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mapHeader.size = htods(sizeof(mapHeader));
3806282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mapHeader.parent.ident = htodl(mParentId);
3807282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mapHeader.count = htodl(N);
3808282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        status_t err = data->writeData(&mapHeader, sizeof(mapHeader));
3809282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (err != NO_ERROR) {
3810282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n");
3811282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return err;
3812282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3813282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3814282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (i=0; i<N; i++) {
3815282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const Item& it = *items.valueAt(i);
3816282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResTable_map map;
3817282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            map.name.ident = htodl(it.bagKeyId);
3818282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            map.value.size = htods(it.parsedValue.size);
3819282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            map.value.dataType = it.parsedValue.dataType;
3820282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            map.value.res0 = it.parsedValue.res0;
3821282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            map.value.data = htodl(it.parsedValue.data);
3822282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            err = data->writeData(&map, sizeof(map));
3823282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (err != NO_ERROR) {
3824282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: out of memory creating Res_value\n");
3825282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return err;
3826282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3827282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            amt += sizeof(map);
3828282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3829282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3830282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return amt;
3831282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3832282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3833282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::ConfigList::appendComment(const String16& comment,
3834282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                              bool onlyIfEmpty)
3835282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3836282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (comment.size() <= 0) {
3837282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
3838282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3839282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (onlyIfEmpty && mComment.size() > 0) {
3840282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
3841282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3842282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mComment.size() > 0) {
3843282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mComment.append(String16("\n"));
3844282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3845282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mComment.append(comment);
3846282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3847282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3848282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::ConfigList::appendTypeComment(const String16& comment)
3849282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3850282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (comment.size() <= 0) {
3851282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
3852282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3853282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mTypeComment.size() > 0) {
3854282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mTypeComment.append(String16("\n"));
3855282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3856282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mTypeComment.append(comment);
3857282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3858282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3859282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
3860282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        const String16& name,
3861282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        const uint32_t ident)
3862282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3863282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    #if 0
3864282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int32_t entryIdx = Res_GETENTRY(ident);
3865282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (entryIdx < 0) {
3866282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sourcePos.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n",
3867282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                String8(mName).string(), String8(name).string(), ident);
3868282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
3869282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3870282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    #endif
3871282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3872282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int32_t typeIdx = Res_GETTYPE(ident);
3873282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (typeIdx >= 0) {
3874282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        typeIdx++;
3875282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mPublicIndex > 0 && mPublicIndex != typeIdx) {
3876282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sourcePos.error("Public resource %s/%s has conflicting type codes for its"
3877282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    " public identifiers (0x%x vs 0x%x).\n",
3878282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(mName).string(), String8(name).string(),
3879282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    mPublicIndex, typeIdx);
3880282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
3881282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3882282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mPublicIndex = typeIdx;
3883282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3884282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3885282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mFirstPublicSourcePos == NULL) {
3886282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mFirstPublicSourcePos = new SourcePos(sourcePos);
3887282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3888282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3889282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (mPublic.indexOfKey(name) < 0) {
3890282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mPublic.add(name, Public(sourcePos, String16(), ident));
3891282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
3892282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Public& p = mPublic.editValueFor(name);
3893282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (p.ident != ident) {
3894282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sourcePos.error("Public resource %s/%s has conflicting public identifiers"
3895282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    " (0x%08x vs 0x%08x).\n"
3896282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    "%s:%d: Originally defined here.\n",
3897282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(mName).string(), String8(name).string(), p.ident, ident,
3898282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    p.sourcePos.file.string(), p.sourcePos.line);
3899282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return UNKNOWN_ERROR;
3900282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3901282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3902282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3903282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
3904282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3905282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3906282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid ResourceTable::Type::canAddEntry(const String16& name)
3907282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3908282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    mCanAddEntries.add(name);
3909282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3910282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3911282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
3912282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                       const SourcePos& sourcePos,
3913282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                       const ResTable_config* config,
3914282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                       bool doSetIndex,
3915282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                       bool overlay,
3916282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                       bool autoAddOverlay)
3917282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
3918282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int pos = -1;
3919282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<ConfigList> c = mConfigs.valueFor(entry);
3920282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (c == NULL) {
3921282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) {
3922282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sourcePos.error("Resource at %s appears in overlay but not"
3923282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            " in the base package; use <add-resource> to add.\n",
3924282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8(entry).string());
3925282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return NULL;
3926282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3927282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        c = new ConfigList(entry, sourcePos);
3928282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mConfigs.add(entry, c);
3929282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        pos = (int)mOrderedConfigs.size();
3930282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOrderedConfigs.add(c);
3931282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (doSetIndex) {
3932282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            c->setEntryIndex(pos);
3933282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3934282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3935282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3936282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ConfigDescription cdesc;
3937282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (config) cdesc = *config;
3938282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3939282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Entry> e = c->getEntries().valueFor(cdesc);
3940282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e == NULL) {
39412412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kIsDebug) {
39422412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            if (config != NULL) {
39432412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
3944282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
39452412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                    "sw%ddp w%ddp h%ddp layout:%d\n",
3946282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      sourcePos.file.string(), sourcePos.line,
3947282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->mcc, config->mnc,
3948282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->language[0] ? config->language[0] : '-',
3949282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->language[1] ? config->language[1] : '-',
3950282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->country[0] ? config->country[0] : '-',
3951282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->country[1] ? config->country[1] : '-',
3952282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->orientation,
3953282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->touchscreen,
3954282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->density,
3955282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->keyboard,
3956282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->inputFlags,
3957282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->navigation,
3958282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->screenWidth,
3959282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->screenHeight,
3960282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->smallestScreenWidthDp,
3961282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->screenWidthDp,
3962282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                      config->screenHeightDp,
39632412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                      config->screenLayout);
39642412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            } else {
39652412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                printf("New entry at %s:%d: NULL config\n",
39662412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe                        sourcePos.file.string(), sourcePos.line);
39672412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe            }
3968282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3969282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        e = new Entry(entry, sourcePos);
3970282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        c->addEntry(cdesc, e);
3971282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        /*
3972282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (doSetIndex) {
3973282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (pos < 0) {
3974282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                for (pos=0; pos<(int)mOrderedConfigs.size(); pos++) {
3975282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (mOrderedConfigs[pos] == c) {
3976282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        break;
3977282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
3978282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3979282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (pos >= (int)mOrderedConfigs.size()) {
3980282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sourcePos.error("Internal error: config not found in mOrderedConfigs when adding entry");
3981282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return NULL;
3982282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
3983282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
3984282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            e->setEntryIndex(pos);
3985282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
3986282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        */
3987282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
3988282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
3989282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return e;
3990282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
3991282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
39929b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinskisp<ResourceTable::ConfigList> ResourceTable::Type::removeEntry(const String16& entry) {
39939b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    ssize_t idx = mConfigs.indexOfKey(entry);
39949b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    if (idx < 0) {
39959b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        return NULL;
39969b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
39979b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
39989b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    sp<ConfigList> removed = mConfigs.valueAt(idx);
39999b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    mConfigs.removeItemsAt(idx);
40009b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
40019b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    Vector<sp<ConfigList> >::iterator iter = std::find(
40029b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            mOrderedConfigs.begin(), mOrderedConfigs.end(), removed);
40039b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    if (iter != mOrderedConfigs.end()) {
40049b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        mOrderedConfigs.erase(iter);
40059b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
40069b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
40079b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    mPublic.removeItem(entry);
40089b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    return removed;
40099b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski}
40109b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
40119b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam LesinskiSortedVector<ConfigDescription> ResourceTable::Type::getUniqueConfigs() const {
40129b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    SortedVector<ConfigDescription> unique;
40139b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    const size_t entryCount = mOrderedConfigs.size();
40149b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    for (size_t i = 0; i < entryCount; i++) {
40159b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (mOrderedConfigs[i] == NULL) {
40169b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            continue;
40179b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
40189b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configs =
40199b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                mOrderedConfigs[i]->getEntries();
40209b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        const size_t configCount = configs.size();
40219b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        for (size_t j = 0; j < configCount; j++) {
40229b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            unique.add(configs.keyAt(j));
40239b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
40249b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
40259b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    return unique;
40269b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski}
40279b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
4028282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Type::applyPublicEntryOrder()
4029282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4030282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = mOrderedConfigs.size();
4031282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<sp<ConfigList> > origOrder(mOrderedConfigs);
4032282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool hasError = false;
4033282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4034282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t i;
4035282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<N; i++) {
4036282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOrderedConfigs.replaceAt(NULL, i);
4037282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4038282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4039282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t NP = mPublic.size();
4040282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("Ordering %d configs from %d public defs\n", N, NP);
4041282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t j;
4042282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (j=0; j<NP; j++) {
4043282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const String16& name = mPublic.keyAt(j);
4044282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const Public& p = mPublic.valueAt(j);
4045282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int32_t idx = Res_GETENTRY(p.ident);
4046282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n",
4047282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //       String8(mName).string(), String8(name).string(), p.ident, N);
4048282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        bool found = false;
4049282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (i=0; i<N; i++) {
4050282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<ConfigList> e = origOrder.itemAt(i);
4051282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            //printf("#%d: \"%s\"\n", i, String8(e->getName()).string());
4052282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (e->getName() == name) {
4053282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (idx >= (int32_t)mOrderedConfigs.size()) {
40549b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    mOrderedConfigs.resize(idx + 1);
40559b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                }
40569b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
40579b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                if (mOrderedConfigs.itemAt(idx) == NULL) {
4058282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    e->setPublic(true);
4059282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    e->setPublicSourcePos(p.sourcePos);
4060282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    mOrderedConfigs.replaceAt(e, idx);
4061282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    origOrder.removeAt(i);
4062282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    N--;
4063282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    found = true;
4064282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
4065282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } else {
4066282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    sp<ConfigList> oe = mOrderedConfigs.itemAt(idx);
4067282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4068282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    p.sourcePos.error("Multiple entry names declared for public entry"
4069282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            " identifier 0x%x in type %s (%s vs %s).\n"
4070282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "%s:%d: Originally defined here.",
4071282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            idx+1, String8(mName).string(),
4072282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8(oe->getName()).string(),
4073282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            String8(name).string(),
4074282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            oe->getPublicSourcePos().file.string(),
4075282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            oe->getPublicSourcePos().line);
4076282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    hasError = true;
4077282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
4078282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
4079282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4080282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4081282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!found) {
4082282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            p.sourcePos.error("Public symbol %s/%s declared here is not defined.",
4083282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(mName).string(), String8(name).string());
4084282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            hasError = true;
4085282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4086282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4087282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4088282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //printf("Copying back in %d non-public configs, have %d\n", N, origOrder.size());
4089282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4090282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (N != origOrder.size()) {
4091282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("Internal error: remaining private symbol count mismatch\n");
4092282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        N = origOrder.size();
4093282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4094282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4095282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    j = 0;
4096282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<N; i++) {
40979b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung Hsieh        const sp<ConfigList>& e = origOrder.itemAt(i);
4098282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // There will always be enough room for the remaining entries.
4099282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (mOrderedConfigs.itemAt(j) != NULL) {
4100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            j++;
4101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOrderedConfigs.replaceAt(e, j);
4103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        j++;
4104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
41062412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe    return hasError ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
4107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4109833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam LesinskiResourceTable::Package::Package(const String16& name, size_t packageId)
4110833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    : mName(name), mPackageId(packageId),
4111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      mTypeStringsMapping(0xffffffff),
4112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski      mKeyStringsMapping(0xffffffff)
4113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<ResourceTable::Type> ResourceTable::Package::getType(const String16& type,
4117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                        const SourcePos& sourcePos,
4118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                        bool doSetIndex)
4119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = mTypes.valueFor(type);
4121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (t == NULL) {
4122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        t = new Type(type, sourcePos);
4123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mTypes.add(type, t);
4124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOrderedTypes.add(t);
4125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (doSetIndex) {
4126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // For some reason the type's index is set to one plus the index
4127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // in the mOrderedTypes list, rather than just the index.
4128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            t->setIndex(mOrderedTypes.size());
4129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return t;
4132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Package::setTypeStrings(const sp<AaptFile>& data)
4135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = setStrings(data, &mTypeStrings, &mTypeStringsMapping);
4137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
4138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: Type string data is corrupt!\n");
413957079519f4610715e4c0668c641575d10f3d4461Adam Lesinski        return err;
4140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
414157079519f4610715e4c0668c641575d10f3d4461Adam Lesinski
414257079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    // Retain a reference to the new data after we've successfully replaced
414357079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    // all uses of the old reference (in setStrings() ).
414457079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    mTypeStringsData = data;
414557079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    return NO_ERROR;
4146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Package::setKeyStrings(const sp<AaptFile>& data)
4149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = setStrings(data, &mKeyStrings, &mKeyStringsMapping);
4151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err != NO_ERROR) {
4152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: Key string data is corrupt!\n");
415357079519f4610715e4c0668c641575d10f3d4461Adam Lesinski        return err;
4154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
415557079519f4610715e4c0668c641575d10f3d4461Adam Lesinski
415657079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    // Retain a reference to the new data after we've successfully replaced
415757079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    // all uses of the old reference (in setStrings() ).
415857079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    mKeyStringsData = data;
415957079519f4610715e4c0668c641575d10f3d4461Adam Lesinski    return NO_ERROR;
4160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Package::setStrings(const sp<AaptFile>& data,
4163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            ResStringPool* strings,
4164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                            DefaultKeyedVector<String16, uint32_t>* mappings)
4165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (data->getData() == NULL) {
4167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return UNKNOWN_ERROR;
4168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    status_t err = strings->setTo(data->getData(), data->getSize());
4171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (err == NO_ERROR) {
4172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const size_t N = strings->size();
4173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (size_t i=0; i<N; i++) {
4174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t len;
4175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mappings->add(String16(strings->stringAt(i, &len)), i);
4176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return err;
4179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatus_t ResourceTable::Package::applyPublicTypeOrder()
4182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t N = mOrderedTypes.size();
4184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    Vector<sp<Type> > origOrder(mOrderedTypes);
4185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t i;
4187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<N; i++) {
4188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOrderedTypes.replaceAt(NULL, i);
4189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<N; i++) {
4192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Type> t = origOrder.itemAt(i);
4193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int32_t idx = t->getPublicIndex();
4194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (idx > 0) {
4195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            idx--;
4196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            while (idx >= (int32_t)mOrderedTypes.size()) {
4197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                mOrderedTypes.add();
4198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
4199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (mOrderedTypes.itemAt(idx) != NULL) {
4200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                sp<Type> ot = mOrderedTypes.itemAt(idx);
4201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                t->getFirstPublicSourcePos().error("Multiple type names declared for public type"
4202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        " identifier 0x%x (%s vs %s).\n"
4203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "%s:%d: Originally defined here.",
4204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        idx, String8(ot->getName()).string(),
4205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String8(t->getName()).string(),
4206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ot->getFirstPublicSourcePos().file.string(),
4207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        ot->getFirstPublicSourcePos().line);
4208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return UNKNOWN_ERROR;
4209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
4210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mOrderedTypes.replaceAt(t, idx);
4211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            origOrder.removeAt(i);
4212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            i--;
4213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            N--;
4214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t j=0;
4218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (i=0; i<N; i++) {
42199b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung Hsieh        const sp<Type>& t = origOrder.itemAt(i);
4220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // There will always be enough room for the remaining types.
4221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        while (mOrderedTypes.itemAt(j) != NULL) {
4222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            j++;
4223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mOrderedTypes.replaceAt(t, j);
4225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NO_ERROR;
4228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
42309b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinskivoid ResourceTable::Package::movePrivateAttrs() {
42319b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    sp<Type> attr = mTypes.valueFor(String16("attr"));
42329b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    if (attr == NULL) {
42339b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        // Nothing to do.
42349b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        return;
42359b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
42369b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42379b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    Vector<sp<ConfigList> > privateAttrs;
42389b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42399b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    bool hasPublic = false;
42409b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    const Vector<sp<ConfigList> >& configs = attr->getOrderedConfigs();
42419b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    const size_t configCount = configs.size();
42429b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    for (size_t i = 0; i < configCount; i++) {
42439b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (configs[i] == NULL) {
42449b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            continue;
42459b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
42469b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42479b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        if (attr->isPublic(configs[i]->getName())) {
42489b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            hasPublic = true;
42499b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        } else {
42509b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            privateAttrs.add(configs[i]);
42519b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
42529b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
42539b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42549b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    // Only if we have public attributes do we create a separate type for
42559b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    // private attributes.
42569b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    if (!hasPublic) {
42579b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        return;
42589b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
42599b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42609b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    // Create a new type for private attributes.
42619b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    sp<Type> privateAttrType = getType(String16(kAttrPrivateType), SourcePos());
42629b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42639b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    const size_t privateAttrCount = privateAttrs.size();
42649b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    for (size_t i = 0; i < privateAttrCount; i++) {
42659b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        const sp<ConfigList>& cl = privateAttrs[i];
42669b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42679b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        // Remove the private attributes from their current type.
42689b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        attr->removeEntry(cl->getName());
42699b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42709b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        // Add it to the new type.
42719b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries = cl->getEntries();
42729b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        const size_t entryCount = entries.size();
42739b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        for (size_t j = 0; j < entryCount; j++) {
42749b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            const sp<Entry>& oldEntry = entries[j];
42759b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            sp<Entry> entry = privateAttrType->getEntry(
42769b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski                    cl->getName(), oldEntry->getPos(), &entries.keyAt(j));
42779b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski            *entry = *oldEntry;
42789b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        }
42799b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42809b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski        // Move the symbols to the new type.
42819b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
42829b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski    }
42839b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski}
42849b624c186cb6059dfb3ec24bfb6386a0fc17b88cAdam Lesinski
4285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
4286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4287833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    if (package != mAssetsPackage) {
4288833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski        return NULL;
4289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4290833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    return mPackages.valueFor(package);
4291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<ResourceTable::Type> ResourceTable::getType(const String16& package,
4294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                               const String16& type,
4295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                               const SourcePos& sourcePos,
4296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                               bool doSetIndex)
4297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p = getPackage(package);
4299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p == NULL) {
4300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return p->getType(type, sourcePos, doSetIndex);
4303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package,
4306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                 const String16& type,
4307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                 const String16& name,
4308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                 const SourcePos& sourcePos,
4309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                 bool overlay,
4310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                 const ResTable_config* config,
4311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                 bool doSetIndex)
4312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = getType(package, type, sourcePos, doSetIndex);
4314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (t == NULL) {
4315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return t->getEntry(name, sourcePos, config, doSetIndex, overlay, mBundle->getAutoAddOverlay());
4318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4320e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinskisp<ResourceTable::ConfigList> ResourceTable::getConfigList(const String16& package,
4321e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const String16& type, const String16& name) const
4322e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski{
4323e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    const size_t packageCount = mOrderedPackages.size();
4324e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    for (size_t pi = 0; pi < packageCount; pi++) {
4325e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const sp<Package>& p = mOrderedPackages[pi];
4326e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        if (p == NULL || p->getName() != package) {
4327e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            continue;
4328e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        }
4329e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4330e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const Vector<sp<Type> >& types = p->getOrderedTypes();
4331e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const size_t typeCount = types.size();
4332e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        for (size_t ti = 0; ti < typeCount; ti++) {
4333e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            const sp<Type>& t = types[ti];
4334e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            if (t == NULL || t->getName() != type) {
4335e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                continue;
4336e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            }
4337e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4338e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            const Vector<sp<ConfigList> >& configs = t->getOrderedConfigs();
4339e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            const size_t configCount = configs.size();
4340e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            for (size_t ci = 0; ci < configCount; ci++) {
4341e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                const sp<ConfigList>& cl = configs[ci];
4342e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                if (cl == NULL || cl->getName() != name) {
4343e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                    continue;
4344e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                }
4345e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4346e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                return cl;
4347e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            }
4348e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        }
4349e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
4350e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    return NULL;
4351e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski}
4352e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskisp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
4354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                       const ResTable_config* config) const
4355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4356833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    size_t pid = Res_GETPACKAGE(resID)+1;
4357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = mOrderedPackages.size();
4358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Package> p;
4359833f3ccbc8f4dd1ec8abb9121988b99ff34ec4c1Adam Lesinski    for (size_t i = 0; i < N; i++) {
4360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sp<Package> check = mOrderedPackages[i];
4361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (check->getAssignedId() == pid) {
4362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            p = check;
4363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
4364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (p == NULL) {
4368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "warning: Package not found for resource #%08x\n", resID);
4369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int tid = Res_GETTYPE(resID);
4373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (tid < 0 || tid >= (int)p->getOrderedTypes().size()) {
4374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "warning: Type not found for resource #%08x\n", resID);
4375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Type> t = p->getOrderedTypes()[tid];
4378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int eid = Res_GETENTRY(resID);
4380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (eid < 0 || eid >= (int)t->getOrderedConfigs().size()) {
4381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
4382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<ConfigList> c = t->getOrderedConfigs()[eid];
4386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (c == NULL) {
4387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
4388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ConfigDescription cdesc;
4392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (config) cdesc = *config;
4393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<Entry> e = c->getEntries().valueFor(cdesc);
4394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (c == NULL) {
4395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "warning: Entry configuration not found for resource #%08x\n", resID);
4396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4398282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4399282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return e;
4400282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4401282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4402282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiconst ResourceTable::Item* ResourceTable::getItem(uint32_t resID, uint32_t attrID) const
4403282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4404282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    sp<const Entry> e = getEntry(resID);
4405282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (e == NULL) {
4406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return NULL;
4407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const size_t N = e->getBag().size();
4410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    for (size_t i=0; i<N; i++) {
4411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const Item& it = e->getBag().valueAt(i);
4412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (it.bagKeyId == 0) {
4413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n",
4414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(e->getName()).string(),
4415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(e->getBag().keyAt(i)).string());
4416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (it.bagKeyId == attrID) {
4418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return &it;
4419282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4420282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4421282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4422282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return NULL;
4423282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
4424282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4425282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool ResourceTable::getItemValue(
4426282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    uint32_t resID, uint32_t attrID, Res_value* outValue)
4427282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
4428282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const Item* item = getItem(resID, attrID);
4429282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4430282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool res = false;
4431282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (item != NULL) {
4432282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (item->evaluating) {
4433282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            sp<const Entry> e = getEntry(resID);
4434282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            const size_t N = e->getBag().size();
4435282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            size_t i;
4436282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (i=0; i<N; i++) {
4437282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (&e->getBag().valueAt(i) == item) {
4438282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
4439282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
4440282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
4441282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n",
4442282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(e->getName()).string(),
4443282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    String8(e->getBag().keyAt(i)).string());
4444282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return false;
4445282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
4446282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        item->evaluating = true;
4447282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        res = stringToValue(outValue, NULL, item->value, false, false, item->bagKeyId);
44482412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        if (kIsDebug) {
4449282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (res) {
4450282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n",
4451282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       resID, attrID, String8(getEntry(resID)->getName()).string(),
4452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       outValue->dataType, outValue->data);
4453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
4454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                printf("getItemValue of #%08x[#%08x]: failed\n",
4455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                       resID, attrID);
4456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
44572412f84064c26b643c722ce914a97c4ec7776c69Andreas Gampe        }
4458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        item->evaluating = false;
4459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
4460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return res;
4461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
446282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
446382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski/**
446428994d8d181c286b39811441ce78399576c2d315Adam Lesinski * Returns the SDK version at which the attribute was
446528994d8d181c286b39811441ce78399576c2d315Adam Lesinski * made public, or -1 if the resource ID is not an attribute
446628994d8d181c286b39811441ce78399576c2d315Adam Lesinski * or is not public.
446782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski */
446828994d8d181c286b39811441ce78399576c2d315Adam Lesinskiint ResourceTable::getPublicAttributeSdkLevel(uint32_t attrId) const {
446928994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if (Res_GETPACKAGE(attrId) + 1 != 0x01 || Res_GETTYPE(attrId) + 1 != 0x01) {
447028994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return -1;
447182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    }
447282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
447382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    uint32_t specFlags;
447482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
447528994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return -1;
447628994d8d181c286b39811441ce78399576c2d315Adam Lesinski    }
447728994d8d181c286b39811441ce78399576c2d315Adam Lesinski
447828994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
447928994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return -1;
448028994d8d181c286b39811441ce78399576c2d315Adam Lesinski    }
448128994d8d181c286b39811441ce78399576c2d315Adam Lesinski
448228994d8d181c286b39811441ce78399576c2d315Adam Lesinski    const size_t entryId = Res_GETENTRY(attrId);
448328994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if (entryId <= 0x021c) {
448428994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return 1;
448528994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x021d) {
448628994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return 2;
448728994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x0269) {
448828994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_CUPCAKE;
448928994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x028d) {
449028994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_DONUT;
449128994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x02ad) {
449228994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_ECLAIR;
449328994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x02b3) {
449428994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_ECLAIR_0_1;
449528994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x02b5) {
449628994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_ECLAIR_MR1;
449728994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x02bd) {
449828994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_FROYO;
449928994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x02cb) {
450028994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_GINGERBREAD;
450128994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x0361) {
450228994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_HONEYCOMB;
450328994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x0366) {
450428994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_HONEYCOMB_MR1;
450528994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x03a6) {
450628994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_HONEYCOMB_MR2;
450728994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x03ae) {
450828994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_JELLY_BEAN;
450928994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x03cc) {
451028994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_JELLY_BEAN_MR1;
451128994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x03da) {
451228994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_JELLY_BEAN_MR2;
451328994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x03f1) {
451428994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_KITKAT;
451528994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x03f6) {
451628994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_KITKAT_WATCH;
451728994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (entryId <= 0x04ce) {
451828994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_LOLLIPOP;
451928994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else {
452028994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // Anything else is marked as defined in
452128994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // SDK_LOLLIPOP_MR1 since after this
452228994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // version no attribute compat work
452328994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // needs to be done.
452428994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return SDK_LOLLIPOP_MR1;
452582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    }
452682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski}
452782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
452828994d8d181c286b39811441ce78399576c2d315Adam Lesinski/**
452928994d8d181c286b39811441ce78399576c2d315Adam Lesinski * First check the Manifest, then check the command line flag.
453028994d8d181c286b39811441ce78399576c2d315Adam Lesinski */
453128994d8d181c286b39811441ce78399576c2d315Adam Lesinskistatic int getMinSdkVersion(const Bundle* bundle) {
453228994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if (bundle->getManifestMinSdkVersion() != NULL && strlen(bundle->getManifestMinSdkVersion()) > 0) {
453328994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return atoi(bundle->getManifestMinSdkVersion());
453428994d8d181c286b39811441ce78399576c2d315Adam Lesinski    } else if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) {
453528994d8d181c286b39811441ce78399576c2d315Adam Lesinski        return atoi(bundle->getMinSdkVersion());
4536e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
453728994d8d181c286b39811441ce78399576c2d315Adam Lesinski    return 0;
4538e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski}
4539e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4540beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinskibool ResourceTable::shouldGenerateVersionedResource(
4541beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        const sp<ResourceTable::ConfigList>& configList,
4542beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        const ConfigDescription& sourceConfig,
4543beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        const int sdkVersionToGenerate) {
4544f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    assert(sdkVersionToGenerate > sourceConfig.sdkVersion);
4545526d73be4a3a2714fa6112769e16fb6cd0194451Adam Lesinski    assert(configList != NULL);
4546f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& entries
4547f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski            = configList->getEntries();
4548f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    ssize_t idx = entries.indexOfKey(sourceConfig);
4549f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski
4550f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    // The source config came from this list, so it should be here.
4551f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    assert(idx >= 0);
4552f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski
4553beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    // The next configuration either only varies in sdkVersion, or it is completely different
4554beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    // and therefore incompatible. If it is incompatible, we must generate the versioned resource.
4555f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski
4556beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    // NOTE: The ordering of configurations takes sdkVersion as higher precedence than other
4557beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    // qualifiers, so we need to iterate through the entire list to be sure there
4558beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    // are no higher sdk level versions of this resource.
4559f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    ConfigDescription tempConfig(sourceConfig);
4560beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    for (size_t i = static_cast<size_t>(idx) + 1; i < entries.size(); i++) {
4561beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        const ConfigDescription& nextConfig = entries.keyAt(i);
4562beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        tempConfig.sdkVersion = nextConfig.sdkVersion;
4563beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        if (tempConfig == nextConfig) {
4564beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski            // The two configs are the same, check the sdk version.
4565beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski            return sdkVersionToGenerate < nextConfig.sdkVersion;
4566beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski        }
4567f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    }
4568beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski
4569beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    // No match was found, so we should generate the versioned resource.
4570beb9e33bfb79847c25aac98e39f3ea620a953ef7Adam Lesinski    return true;
4571f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski}
4572f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski
457382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski/**
457482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * Modifies the entries in the resource table to account for compatibility
457582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * issues with older versions of Android.
457682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
457782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * This primarily handles the issue of private/public attribute clashes
457882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * in framework resources.
457982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
458082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * AAPT has traditionally assigned resource IDs to public attributes,
458182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * and then followed those public definitions with private attributes.
458282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
458382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * --- PUBLIC ---
458482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010234 | attr/color
458582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010235 | attr/background
458682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
458782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * --- PRIVATE ---
458882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010236 | attr/secret
458982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010237 | attr/shhh
459082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
459182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * Each release, when attributes are added, they take the place of the private
459282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * attributes and the private attributes are shifted down again.
459382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
459482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * --- PUBLIC ---
459582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010234 | attr/color
459682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010235 | attr/background
459782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010236 | attr/shinyNewAttr
459882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010237 | attr/highlyValuedFeature
459982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
460082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * --- PRIVATE ---
460182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010238 | attr/secret
460282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * | 0x01010239 | attr/shhh
460382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
460482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * Platform code may look for private attributes set in a theme. If an app
460582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * compiled against a newer version of the platform uses a new public
460682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * attribute that happens to have the same ID as the private attribute
460782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * the older platform is expecting, then the behavior is undefined.
460882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski *
460982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * We get around this by detecting any newly defined attributes (in L),
461082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * copy the resource into a -v21 qualified resource, and delete the
461182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * attribute from the original resource. This ensures that older platforms
461282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * don't see the new attribute, but when running on L+ platforms, the
461382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski * attribute will be respected.
461482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski */
461582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinskistatus_t ResourceTable::modifyForCompat(const Bundle* bundle) {
461628994d8d181c286b39811441ce78399576c2d315Adam Lesinski    const int minSdk = getMinSdkVersion(bundle);
461728994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if (minSdk >= SDK_LOLLIPOP_MR1) {
461828994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // Lollipop MR1 and up handles public attributes differently, no
461928994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // need to do any compat modifications.
4620e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        return NO_ERROR;
462182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    }
462282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
462382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    const String16 attr16("attr");
462482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
462582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    const size_t packageCount = mOrderedPackages.size();
462682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    for (size_t pi = 0; pi < packageCount; pi++) {
462782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        sp<Package> p = mOrderedPackages.itemAt(pi);
462882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        if (p == NULL || p->getTypes().size() == 0) {
462982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            // Empty, skip!
463082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            continue;
463182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        }
463282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
463382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        const size_t typeCount = p->getOrderedTypes().size();
463482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        for (size_t ti = 0; ti < typeCount; ti++) {
463582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            sp<Type> t = p->getOrderedTypes().itemAt(ti);
463682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            if (t == NULL) {
463782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                continue;
463882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            }
463982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
464082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            const size_t configCount = t->getOrderedConfigs().size();
464182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            for (size_t ci = 0; ci < configCount; ci++) {
464282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
464382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                if (c == NULL) {
464482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    continue;
464582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                }
464682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
464782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                Vector<key_value_pair_t<ConfigDescription, sp<Entry> > > entriesToAdd;
464882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries =
464982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                        c->getEntries();
465082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                const size_t entryCount = entries.size();
465182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                for (size_t ei = 0; ei < entryCount; ei++) {
46529b8528fee4eed35b8e887ded0851d08eb2b10db6Chih-Hung Hsieh                    const sp<Entry>& e = entries.valueAt(ei);
465382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    if (e == NULL || e->getType() != Entry::TYPE_BAG) {
465482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                        continue;
465582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    }
465682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
465782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    const ConfigDescription& config = entries.keyAt(ei);
465828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                    if (config.sdkVersion >= SDK_LOLLIPOP_MR1) {
465982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                        continue;
466082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    }
466182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
466228994d8d181c286b39811441ce78399576c2d315Adam Lesinski                    KeyedVector<int, Vector<String16> > attributesToRemove;
466382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    const KeyedVector<String16, Item>& bag = e->getBag();
466482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    const size_t bagCount = bag.size();
466582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    for (size_t bi = 0; bi < bagCount; bi++) {
466682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                        const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
466728994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        const int sdkLevel = getPublicAttributeSdkLevel(attrId);
466828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
466928994d8d181c286b39811441ce78399576c2d315Adam Lesinski                            AaptUtil::appendValue(attributesToRemove, sdkLevel, bag.keyAt(bi));
467082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                        }
467182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    }
467282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
467382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    if (attributesToRemove.isEmpty()) {
467482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                        continue;
467582a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    }
467682a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
467728994d8d181c286b39811441ce78399576c2d315Adam Lesinski                    const size_t sdkCount = attributesToRemove.size();
467828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                    for (size_t i = 0; i < sdkCount; i++) {
467928994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        const int sdkLevel = attributesToRemove.keyAt(i);
468028994d8d181c286b39811441ce78399576c2d315Adam Lesinski
4681f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                        if (!shouldGenerateVersionedResource(c, config, sdkLevel)) {
4682f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                            // There is a style that will override this generated one.
4683f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                            continue;
4684f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                        }
4685f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski
468628994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        // Duplicate the entry under the same configuration
468728994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        // but with sdkVersion == sdkLevel.
468828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        ConfigDescription newConfig(config);
468928994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        newConfig.sdkVersion = sdkLevel;
469028994d8d181c286b39811441ce78399576c2d315Adam Lesinski
469128994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        sp<Entry> newEntry = new Entry(*e);
469228994d8d181c286b39811441ce78399576c2d315Adam Lesinski
469328994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        // Remove all items that have a higher SDK level than
469428994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        // the one we are synthesizing.
469528994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        for (size_t j = 0; j < sdkCount; j++) {
469628994d8d181c286b39811441ce78399576c2d315Adam Lesinski                            if (j == i) {
469728994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                continue;
469828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                            }
469928994d8d181c286b39811441ce78399576c2d315Adam Lesinski
470028994d8d181c286b39811441ce78399576c2d315Adam Lesinski                            if (attributesToRemove.keyAt(j) > sdkLevel) {
470128994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                const size_t attrCount = attributesToRemove[j].size();
470228994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                for (size_t k = 0; k < attrCount; k++) {
470328994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                    newEntry->removeFromBag(attributesToRemove[j][k]);
470428994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                }
470528994d8d181c286b39811441ce78399576c2d315Adam Lesinski                            }
470628994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        }
470728994d8d181c286b39811441ce78399576c2d315Adam Lesinski
470828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
470928994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                newConfig, newEntry));
471028994d8d181c286b39811441ce78399576c2d315Adam Lesinski                    }
471182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
471282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    // Remove the attribute from the original.
471382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    for (size_t i = 0; i < attributesToRemove.size(); i++) {
471428994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        for (size_t j = 0; j < attributesToRemove[i].size(); j++) {
471528994d8d181c286b39811441ce78399576c2d315Adam Lesinski                            e->removeFromBag(attributesToRemove[i][j]);
471628994d8d181c286b39811441ce78399576c2d315Adam Lesinski                        }
471782a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                    }
471882a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                }
471982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
472082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                const size_t entriesToAddCount = entriesToAdd.size();
472182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                for (size_t i = 0; i < entriesToAddCount; i++) {
4722f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                    assert(entries.indexOfKey(entriesToAdd[i].key) < 0);
472382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
4724f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    if (bundle->getVerbose()) {
4725f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                        entriesToAdd[i].value->getPos()
4726f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                                .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
472728994d8d181c286b39811441ce78399576c2d315Adam Lesinski                                        entriesToAdd[i].key.sdkVersion,
4728f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                                        String8(p->getName()).string(),
4729f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                                        String8(t->getName()).string(),
4730f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                                        String8(entriesToAdd[i].value->getName()).string(),
4731f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                                        entriesToAdd[i].key.toString().string());
4732f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    }
473382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski
4734978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski                    sp<Entry> newEntry = t->getEntry(c->getName(),
4735978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski                            entriesToAdd[i].value->getPos(),
4736978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski                            &entriesToAdd[i].key);
4737978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski
4738978ab9d92934b79409638cf220de3002fea8d505Adam Lesinski                    *newEntry = *entriesToAdd[i].value;
473982a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski                }
474082a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski            }
474182a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski        }
474282a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    }
474382a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski    return NO_ERROR;
474482a2dd8efe48d3a4e04655f01329da857ace4b7dAdam Lesinski}
4745e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
47464d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Arakiconst String16 kTransitionElements[] = {
47474d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("fade"),
47484d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("changeBounds"),
47494d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("slide"),
47504d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("explode"),
47514d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("changeImageTransform"),
47524d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("changeTransform"),
47534d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("changeClipBounds"),
47544d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("autoTransition"),
47554d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("recolor"),
47564d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("changeScroll"),
47574d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("transitionSet"),
47584d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("transition"),
47594d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    String16("transitionManager"),
47604d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki};
47614d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki
47624d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Arakistatic bool IsTransitionElement(const String16& name) {
47634d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    for (int i = 0, size = sizeof(kTransitionElements) / sizeof(kTransitionElements[0]);
47644d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki         i < size; ++i) {
47654d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki        if (name == kTransitionElements[i]) {
47664d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki            return true;
47674d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki        }
47684d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    }
47694d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki    return false;
47704d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki}
47714d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki
4772cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinskibool ResourceTable::versionForCompat(const Bundle* bundle, const String16& resourceName,
4773cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski                                         const sp<AaptFile>& target, const sp<XMLNode>& root) {
4774cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    XMLNode* node = root.get();
4775cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    while (node->getType() != XMLNode::TYPE_ELEMENT) {
4776cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        // We're assuming the root element is what we're looking for, which can only be under a
4777cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        // bunch of namespace declarations.
4778cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        if (node->getChildren().size() != 1) {
4779cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski          // Not sure what to do, bail.
4780cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski          return false;
4781cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        }
4782cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        node = node->getChildren().itemAt(0).get();
4783cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    }
4784cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4785cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    if (node->getElementNamespace().size() != 0) {
4786cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        // Not something we care about.
4787cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        return false;
4788cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    }
4789cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4790cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    int versionedSdk = 0;
4791cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    if (node->getElementName() == String16("adaptive-icon")) {
4792cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        versionedSdk = SDK_O;
4793cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    }
4794cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4795cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    const int minSdkVersion = getMinSdkVersion(bundle);
4796cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    const ConfigDescription config(target->getGroupEntry().toParams());
4797cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    if (versionedSdk <= minSdkVersion || versionedSdk <= config.sdkVersion) {
4798cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        return false;
4799cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    }
4800cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4801cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
4802cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            String16(target->getResourceType()), resourceName);
4803cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    if (!shouldGenerateVersionedResource(cl, config, versionedSdk)) {
4804cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski        return false;
4805cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    }
4806cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4807cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    // Remove the original entry.
4808cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    cl->removeEntry(config);
4809cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4810cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    // We need to wholesale version this file.
4811cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    ConfigDescription newConfig(config);
4812cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    newConfig.sdkVersion = versionedSdk;
4813cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
4814cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            AaptGroupEntry(newConfig), target->getResourceType());
4815cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    String8 resPath = String8::format("res/%s/%s.xml",
4816cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
4817cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            String8(resourceName).string());
4818cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    resPath.convertToResPath();
4819cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4820cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    // Add a resource table entry.
4821cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    addEntry(SourcePos(),
4822cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            String16(mAssets->getPackage()),
4823cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            String16(target->getResourceType()),
4824cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            resourceName,
4825cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            String16(resPath),
4826cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            NULL,
4827cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski            &newConfig);
4828cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4829cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    // Schedule this to be compiled.
4830cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    CompileResourceWorkItem item;
4831cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    item.resourceName = resourceName;
4832cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    item.resPath = resPath;
4833cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    item.file = newFile;
4834cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    item.xmlRoot = root->clone();
483554b58ba5cc2c341b39355e265f760fe0654f77a7Adam Lesinski    item.needsCompiling = true;
4836cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    mWorkQueue.push(item);
4837cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4838cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    // Now mark the old entry as deleted.
4839cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski    return true;
4840cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski}
4841cf1f1d9128853f0fa0cef657e2bbb7bf6904c732Adam Lesinski
4842e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinskistatus_t ResourceTable::modifyForCompat(const Bundle* bundle,
4843e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                                        const String16& resourceName,
4844e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                                        const sp<AaptFile>& target,
4845e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                                        const sp<XMLNode>& root) {
48466e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski    const String16 vector16("vector");
48476e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski    const String16 animatedVector16("animated-vector");
4848010df88f90a40f8c521ccde8d6a541e70a044fb7ztenghui    const String16 pathInterpolator16("pathInterpolator");
4849205548561c67a3c05163d17057a1fc76a338ec15ztenghui    const String16 objectAnimator16("objectAnimator");
4850ab2a38c03d54fad1ed0873ac091959ee38823cd6ztenghui    const String16 gradient16("gradient");
4851e78a8169665c19b5539508f113093b6c2a4b80deNick Butcher    const String16 animatedSelector16("animated-selector");
48526e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski
485328994d8d181c286b39811441ce78399576c2d315Adam Lesinski    const int minSdk = getMinSdkVersion(bundle);
485428994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if (minSdk >= SDK_LOLLIPOP_MR1) {
485528994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // Lollipop MR1 and up handles public attributes differently, no
485628994d8d181c286b39811441ce78399576c2d315Adam Lesinski        // need to do any compat modifications.
4857e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        return NO_ERROR;
4858e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
4859e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
486028994d8d181c286b39811441ce78399576c2d315Adam Lesinski    const ConfigDescription config(target->getGroupEntry().toParams());
486128994d8d181c286b39811441ce78399576c2d315Adam Lesinski    if (target->getResourceType() == "" || config.sdkVersion >= SDK_LOLLIPOP_MR1) {
48626e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski        // Skip resources that have no type (AndroidManifest.xml) or are already version qualified
48636e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski        // with v21 or higher.
4864e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        return NO_ERROR;
4865e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
4866e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4867ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski    sp<XMLNode> newRoot = NULL;
4868f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    int sdkVersionToGenerate = SDK_LOLLIPOP_MR1;
4869e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4870e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    Vector<sp<XMLNode> > nodesToVisit;
4871e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    nodesToVisit.push(root);
4872e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    while (!nodesToVisit.isEmpty()) {
4873e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        sp<XMLNode> node = nodesToVisit.top();
4874e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        nodesToVisit.pop();
4875e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
48766e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski        if (bundle->getNoVersionVectors() && (node->getElementName() == vector16 ||
4877010df88f90a40f8c521ccde8d6a541e70a044fb7ztenghui                    node->getElementName() == animatedVector16 ||
4878205548561c67a3c05163d17057a1fc76a338ec15ztenghui                    node->getElementName() == objectAnimator16 ||
4879ab2a38c03d54fad1ed0873ac091959ee38823cd6ztenghui                    node->getElementName() == pathInterpolator16 ||
4880e78a8169665c19b5539508f113093b6c2a4b80deNick Butcher                    node->getElementName() == gradient16 ||
4881e78a8169665c19b5539508f113093b6c2a4b80deNick Butcher                    node->getElementName() == animatedSelector16)) {
48826e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski            // We were told not to version vector tags, so skip the children here.
48836e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski            continue;
48846e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski        }
48856e46056abc1c2803ed7f195bab169bbb1cacec6bAdam Lesinski
48864d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki        if (bundle->getNoVersionTransitions() && (IsTransitionElement(node->getElementName()))) {
48874d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki            // We were told not to version transition tags, so skip the children here.
48884d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki            continue;
48894d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki        }
48904d35cca96ce55eb29d1948086214f91ae94e9adbYuichi Araki
4891e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes();
4892ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski        for (size_t i = 0; i < attrs.size(); i++) {
4893e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            const XMLNode::attribute_entry& attr = attrs[i];
489428994d8d181c286b39811441ce78399576c2d315Adam Lesinski            const int sdkLevel = getPublicAttributeSdkLevel(attr.nameResId);
489528994d8d181c286b39811441ce78399576c2d315Adam Lesinski            if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
4896ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                if (newRoot == NULL) {
4897ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                    newRoot = root->clone();
4898ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                }
4899ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski
490028994d8d181c286b39811441ce78399576c2d315Adam Lesinski                // Find the smallest sdk version that we need to synthesize for
490128994d8d181c286b39811441ce78399576c2d315Adam Lesinski                // and do that one. Subsequent versions will be processed on
490228994d8d181c286b39811441ce78399576c2d315Adam Lesinski                // the next pass.
4903f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                sdkVersionToGenerate = std::min(sdkLevel, sdkVersionToGenerate);
490428994d8d181c286b39811441ce78399576c2d315Adam Lesinski
4905ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                if (bundle->getVerbose()) {
4906ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                    SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
4907ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                            "removing attribute %s%s%s from <%s>",
4908ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                            String8(attr.ns).string(),
4909ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                            (attr.ns.size() == 0 ? "" : ":"),
4910ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                            String8(attr.name).string(),
4911ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                            String8(node->getElementName()).string());
4912ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                }
4913ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                node->removeAttribute(i);
4914ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski                i--;
4915e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            }
4916e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        }
4917e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4918e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        // Schedule a visit to the children.
4919e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const Vector<sp<XMLNode> >& children = node->getChildren();
4920e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        const size_t childCount = children.size();
4921e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        for (size_t i = 0; i < childCount; i++) {
4922e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            nodesToVisit.push(children[i]);
4923e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        }
4924e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
4925e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4926ea4e5ecc27793b5c1dd2eda291f752b3f900ee6cAdam Lesinski    if (newRoot == NULL) {
4927e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        return NO_ERROR;
4928e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
4929e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4930e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    // Look to see if we already have an overriding v21 configuration.
4931e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
4932e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski            String16(target->getResourceType()), resourceName);
4933f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski    if (shouldGenerateVersionedResource(cl, config, sdkVersionToGenerate)) {
4934e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        // We don't have an overriding entry for v21, so we must duplicate this one.
4935f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski        ConfigDescription newConfig(config);
4936f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski        newConfig.sdkVersion = sdkVersionToGenerate;
4937e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
4938e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                AaptGroupEntry(newConfig), target->getResourceType());
493907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        String8 resPath = String8::format("res/%s/%s.xml",
4940e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
494107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                String8(resourceName).string());
4942e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        resPath.convertToResPath();
4943e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4944e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        // Add a resource table entry.
4945f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski        if (bundle->getVerbose()) {
4946f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski            SourcePos(target->getSourceFile(), -1).printf(
4947f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
494828994d8d181c286b39811441ce78399576c2d315Adam Lesinski                    newConfig.sdkVersion,
4949f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    mAssets->getPackage().string(),
4950f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    newFile->getResourceType().string(),
4951f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    String8(resourceName).string(),
4952f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski                    newConfig.toString().string());
4953f15de2e2151ae48338afd27f3ebd33fce5009103Adam Lesinski        }
4954e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4955e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        addEntry(SourcePos(),
4956e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                String16(mAssets->getPackage()),
4957e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                String16(target->getResourceType()),
4958e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                resourceName,
4959e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                String16(resPath),
4960e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                NULL,
4961e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski                &newConfig);
4962e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski
4963e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        // Schedule this to be compiled.
4964e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        CompileResourceWorkItem item;
4965e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        item.resourceName = resourceName;
4966e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        item.resPath = resPath;
4967e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        item.file = newFile;
496807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        item.xmlRoot = newRoot;
496907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        item.needsCompiling = false;    // This step occurs after we parse/assign, so we don't need
497007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                        // to do it again.
4971e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski        mWorkQueue.push(item);
4972e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    }
4973e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski    return NO_ERROR;
4974e572c011feabf6319ba836cf5bc4c3baa0ba6a85Adam Lesinski}
4975de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski
4976f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinskivoid ResourceTable::getDensityVaryingResources(
4977f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski        KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) {
4978de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski    const ConfigDescription nullConfig;
4979de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski
4980de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski    const size_t packageCount = mOrderedPackages.size();
4981de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski    for (size_t p = 0; p < packageCount; p++) {
4982de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski        const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes();
4983de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski        const size_t typeCount = types.size();
4984de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski        for (size_t t = 0; t < typeCount; t++) {
4985081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski            const sp<Type>& type = types[t];
4986081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski            if (type == NULL) {
4987081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                continue;
4988081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski            }
4989081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski
4990081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski            const Vector<sp<ConfigList> >& configs = type->getOrderedConfigs();
4991de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski            const size_t configCount = configs.size();
4992de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski            for (size_t c = 0; c < configCount; c++) {
4993081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                const sp<ConfigList>& configList = configs[c];
4994081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                if (configList == NULL) {
4995081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                    continue;
4996081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                }
4997081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski
4998f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries
4999081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                        = configList->getEntries();
5000de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                const size_t configEntryCount = configEntries.size();
5001de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                for (size_t ce = 0; ce < configEntryCount; ce++) {
5002081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                    const sp<Entry>& entry = configEntries.valueAt(ce);
5003081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                    if (entry == NULL) {
5004081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                        continue;
5005081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                    }
5006081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski
5007de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                    const ConfigDescription& config = configEntries.keyAt(ce);
5008de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                    if (AaptConfig::isDensityOnly(config)) {
5009de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                        // This configuration only varies with regards to density.
5010f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                        const Symbol symbol(
5011f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                                mOrderedPackages[p]->getName(),
5012081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                                type->getName(),
5013081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                                configList->getName(),
5014f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                                getResId(mOrderedPackages[p], types[t],
5015081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski                                         configList->getEntryIndex()));
5016081d1b4cf602fdd7302b597e6bf902cb415bc3a8Adam Lesinski
5017de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski
5018f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                        AaptUtil::appendValue(resources, symbol,
5019f45d2fad2ecd3cb3c4aeee3014763e01b59eab09Adam Lesinski                                              SymbolDefinition(symbol, config, entry->getPos()));
5020de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                    }
5021de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski                }
5022de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski            }
5023de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski        }
5024de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski    }
5025de7de47fef1dcaa26d553665d89e4d3792325c3fAdam Lesinski}
502607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
502707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinskistatic String16 buildNamespace(const String16& package) {
502807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    return String16("http://schemas.android.com/apk/res/") + package;
502907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski}
503007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
503107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinskistatic sp<XMLNode> findOnlyChildElement(const sp<XMLNode>& parent) {
503207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    const Vector<sp<XMLNode> >& children = parent->getChildren();
503307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    sp<XMLNode> onlyChild;
503407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    for (size_t i = 0; i < children.size(); i++) {
503507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (children[i]->getType() != XMLNode::TYPE_CDATA) {
503607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            if (onlyChild != NULL) {
503707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                return NULL;
503807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            }
503907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            onlyChild = children[i];
504007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
504107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    }
504207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    return onlyChild;
504307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski}
504407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
504507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski/**
504607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * Detects use of the `bundle' format and extracts nested resources into their own top level
504707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * resources. The bundle format looks like this:
504807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *
504907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * <!-- res/drawable/bundle.xml -->
505007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * <animated-vector xmlns:aapt="http://schemas.android.com/aapt">
505107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *   <aapt:attr name="android:drawable">
505207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *     <vector android:width="60dp"
505307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *             android:height="60dp">
505407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *       <path android:name="v"
505507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *             android:fillColor="#000000"
505607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *             android:pathData="M300,70 l 0,-70 70,..." />
505707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *     </vector>
505807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *   </aapt:attr>
505907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * </animated-vector>
506007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *
506107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * When AAPT sees the <aapt:attr> tag, it will extract its single element and its children
506207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * into a new high-level resource, assigning it a name and ID. Then value of the `name`
506307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * attribute must be a resource attribute. That resource attribute is inserted into the parent
506407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * with the reference to the extracted resource as the value.
506507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *
506607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * <!-- res/drawable/bundle.xml -->
506707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * <animated-vector android:drawable="@drawable/bundle_1.xml">
506807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * </animated-vector>
506907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *
507007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * <!-- res/drawable/bundle_1.xml -->
507107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * <vector android:width="60dp"
507207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *         android:height="60dp">
507307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *   <path android:name="v"
507407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *         android:fillColor="#000000"
507507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski *         android:pathData="M300,70 l 0,-70 70,..." />
507607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski * </vector>
507707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski */
507807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinskistatus_t ResourceTable::processBundleFormat(const Bundle* bundle,
507907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                            const String16& resourceName,
508007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                            const sp<AaptFile>& target,
508107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                            const sp<XMLNode>& root) {
508207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    Vector<sp<XMLNode> > namespaces;
508307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    if (root->getType() == XMLNode::TYPE_NAMESPACE) {
508407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        namespaces.push(root);
508507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    }
508607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    return processBundleFormatImpl(bundle, resourceName, target, root, &namespaces);
508707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski}
508807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
508907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinskistatus_t ResourceTable::processBundleFormatImpl(const Bundle* bundle,
509007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                const String16& resourceName,
509107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                const sp<AaptFile>& target,
509207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                const sp<XMLNode>& parent,
509307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                Vector<sp<XMLNode> >* namespaces) {
509407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    const String16 kAaptNamespaceUri16("http://schemas.android.com/aapt");
509507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    const String16 kName16("name");
509607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    const String16 kAttr16("attr");
509707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    const String16 kAssetPackage16(mAssets->getPackage());
509807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
509907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    Vector<sp<XMLNode> >& children = parent->getChildren();
510007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    for (size_t i = 0; i < children.size(); i++) {
510107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        const sp<XMLNode>& child = children[i];
510207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
510307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (child->getType() == XMLNode::TYPE_CDATA) {
510407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            continue;
510507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        } else if (child->getType() == XMLNode::TYPE_NAMESPACE) {
510607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            namespaces->push(child);
510707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
510807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
510907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (child->getElementNamespace() != kAaptNamespaceUri16 ||
511007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                child->getElementName() != kAttr16) {
511107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            status_t result = processBundleFormatImpl(bundle, resourceName, target, child,
511207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                      namespaces);
511307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            if (result != NO_ERROR) {
511407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                return result;
511507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            }
511607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
511707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            if (child->getType() == XMLNode::TYPE_NAMESPACE) {
511807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                namespaces->pop();
511907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            }
512007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            continue;
512107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
512207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
512307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // This is the <aapt:attr> tag. Look for the 'name' attribute.
512407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        SourcePos source(child->getFilename(), child->getStartLineNumber());
512507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
512607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        sp<XMLNode> nestedRoot = findOnlyChildElement(child);
512707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (nestedRoot == NULL) {
512807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            source.error("<%s:%s> must have exactly one child element",
512907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                         String8(child->getElementNamespace()).string(),
513007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                         String8(child->getElementName()).string());
513107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            return UNKNOWN_ERROR;
513207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
513307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
513407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Find the special attribute 'parent-attr'. This attribute's value contains
513507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // the resource attribute for which this element should be assigned in the parent.
513607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        const XMLNode::attribute_entry* attr = child->getAttribute(String16(), kName16);
513707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (attr == NULL) {
513807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            source.error("inline resource definition must specify an attribute via 'name'");
513907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            return UNKNOWN_ERROR;
514007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
514107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
514207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Parse the attribute name.
514307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        const char* errorMsg = NULL;
514407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        String16 attrPackage, attrType, attrName;
514507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        bool result = ResTable::expandResourceRef(attr->string.string(),
514607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                  attr->string.size(),
514707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                  &attrPackage, &attrType, &attrName,
514807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                  &kAttr16, &kAssetPackage16,
514907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                  &errorMsg, NULL);
515007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (!result) {
515107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            source.error("invalid attribute name for 'name': %s", errorMsg);
515207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            return UNKNOWN_ERROR;
515307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
515407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
515507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (attrType != kAttr16) {
515607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            // The value of the 'name' attribute must be an attribute reference.
515707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            source.error("value of 'name' must be an attribute reference.");
515807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            return UNKNOWN_ERROR;
515907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
516007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
516107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Generate a name for this nested resource and try to add it to the table.
516207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // We do this in a loop because the name may be taken, in which case we will
516307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // increment a suffix until we succeed.
516407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        String8 nestedResourceName;
516507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        String8 nestedResourcePath;
516607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        int suffix = 1;
516707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        while (true) {
516807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            // This child element will be extracted into its own resource file.
516907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            // Generate a name and path for it from its parent.
517007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            nestedResourceName = String8::format("%s_%d",
517107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                        String8(resourceName).string(), suffix++);
517207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            nestedResourcePath = String8::format("res/%s/%s.xml",
517307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                        target->getGroupEntry().toDirName(target->getResourceType())
517407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                               .string(),
517507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                        nestedResourceName.string());
517607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
517707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            // Lookup or create the entry for this name.
517807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            sp<Entry> entry = getEntry(kAssetPackage16,
517907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                       String16(target->getResourceType()),
518007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                       String16(nestedResourceName),
518107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                       source,
518207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                       false,
518307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                       &target->getGroupEntry().toParams(),
518407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                       true);
518507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            if (entry == NULL) {
518607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                return UNKNOWN_ERROR;
518707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            }
518807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
518907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            if (entry->getType() == Entry::TYPE_UNKNOWN) {
519007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                // The value for this resource has never been set,
519107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                // meaning we're good!
519207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                entry->setItem(source, String16(nestedResourcePath));
519307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                break;
519407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            }
519507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
519607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            // We failed (name already exists), so try with a different name
519707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            // (increment the suffix).
519807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
519907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
520007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (bundle->getVerbose()) {
520107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            source.printf("generating nested resource %s:%s/%s",
520207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                    mAssets->getPackage().string(), target->getResourceType().string(),
520307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                    nestedResourceName.string());
520407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
520507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
520607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Build the attribute reference and assign it to the parent.
520707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        String16 nestedResourceRef = String16(String8::format("@%s:%s/%s",
520807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                    mAssets->getPackage().string(), target->getResourceType().string(),
520907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                    nestedResourceName.string()));
521007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
521107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        String16 attrNs = buildNamespace(attrPackage);
521207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        if (parent->getAttribute(attrNs, attrName) != NULL) {
521307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            SourcePos(parent->getFilename(), parent->getStartLineNumber())
521407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                    .error("parent of nested resource already defines attribute '%s:%s'",
521507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                           String8(attrPackage).string(), String8(attrName).string());
521607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            return UNKNOWN_ERROR;
521707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
521807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
521907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Add the reference to the inline resource.
522007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        parent->addAttribute(attrNs, attrName, nestedResourceRef);
522107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
522207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Remove the <aapt:attr> child element from here.
522307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        children.removeAt(i);
522407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        i--;
522507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
522607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Append all namespace declarations that we've seen on this branch in the XML tree
522707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // to this resource.
522807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // We do this because the order of namespace declarations and prefix usage is determined
522907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // by the developer and we do not want to override any decisions. Be conservative.
523007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        for (size_t nsIndex = namespaces->size(); nsIndex > 0; nsIndex--) {
523107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            const sp<XMLNode>& ns = namespaces->itemAt(nsIndex - 1);
523207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            sp<XMLNode> newNs = XMLNode::newNamespace(ns->getFilename(), ns->getNamespacePrefix(),
523307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                                      ns->getNamespaceUri());
523407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            newNs->addChild(nestedRoot);
523507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski            nestedRoot = newNs;
523607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        }
523707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski
523807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        // Schedule compilation of the nested resource.
523907dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        CompileResourceWorkItem workItem;
524007dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        workItem.resPath = nestedResourcePath;
524107dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        workItem.resourceName = String16(nestedResourceName);
524207dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        workItem.xmlRoot = nestedRoot;
524307dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        workItem.file = new AaptFile(target->getSourceFile(), target->getGroupEntry(),
524407dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski                                     target->getResourceType());
524507dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski        mWorkQueue.push(workItem);
524607dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    }
524707dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski    return NO_ERROR;
524807dfd2d8642f8a3630ca6429f740865a0c0bfdf7Adam Lesinski}
5249