1*d57664e9SAndroid Build Coastguard Worker //
2*d57664e9SAndroid Build Coastguard Worker // Copyright 2006 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker //
4*d57664e9SAndroid Build Coastguard Worker // Build resource files from raw assets.
5*d57664e9SAndroid Build Coastguard Worker //
6*d57664e9SAndroid Build Coastguard Worker
7*d57664e9SAndroid Build Coastguard Worker #include "ResourceTable.h"
8*d57664e9SAndroid Build Coastguard Worker
9*d57664e9SAndroid Build Coastguard Worker #include "AaptUtil.h"
10*d57664e9SAndroid Build Coastguard Worker #include "XMLNode.h"
11*d57664e9SAndroid Build Coastguard Worker #include "ResourceFilter.h"
12*d57664e9SAndroid Build Coastguard Worker #include "ResourceIdCache.h"
13*d57664e9SAndroid Build Coastguard Worker #include "SdkConstants.h"
14*d57664e9SAndroid Build Coastguard Worker #include "Utils.h"
15*d57664e9SAndroid Build Coastguard Worker
16*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
17*d57664e9SAndroid Build Coastguard Worker #include <androidfw/PathUtils.h>
18*d57664e9SAndroid Build Coastguard Worker #include <androidfw/ResourceTypes.h>
19*d57664e9SAndroid Build Coastguard Worker #include <utils/ByteOrder.h>
20*d57664e9SAndroid Build Coastguard Worker #include <utils/TypeHelpers.h>
21*d57664e9SAndroid Build Coastguard Worker #include <stdarg.h>
22*d57664e9SAndroid Build Coastguard Worker
23*d57664e9SAndroid Build Coastguard Worker // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
24*d57664e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
25*d57664e9SAndroid Build Coastguard Worker # define STATUST(x) x
26*d57664e9SAndroid Build Coastguard Worker #else
27*d57664e9SAndroid Build Coastguard Worker # define STATUST(x) (status_t)x
28*d57664e9SAndroid Build Coastguard Worker #endif
29*d57664e9SAndroid Build Coastguard Worker
30*d57664e9SAndroid Build Coastguard Worker // Set to true for noisy debug output.
31*d57664e9SAndroid Build Coastguard Worker static const bool kIsDebug = false;
32*d57664e9SAndroid Build Coastguard Worker
33*d57664e9SAndroid Build Coastguard Worker #if PRINT_STRING_METRICS
34*d57664e9SAndroid Build Coastguard Worker static const bool kPrintStringMetrics = true;
35*d57664e9SAndroid Build Coastguard Worker #else
36*d57664e9SAndroid Build Coastguard Worker static const bool kPrintStringMetrics = false;
37*d57664e9SAndroid Build Coastguard Worker #endif
38*d57664e9SAndroid Build Coastguard Worker
39*d57664e9SAndroid Build Coastguard Worker static const char* kAttrPrivateType = "^attr-private";
40*d57664e9SAndroid Build Coastguard Worker
compileXmlFile(const Bundle * bundle,const sp<AaptAssets> & assets,const String16 & resourceName,const sp<AaptFile> & target,ResourceTable * table,int options)41*d57664e9SAndroid Build Coastguard Worker status_t compileXmlFile(const Bundle* bundle,
42*d57664e9SAndroid Build Coastguard Worker const sp<AaptAssets>& assets,
43*d57664e9SAndroid Build Coastguard Worker const String16& resourceName,
44*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target,
45*d57664e9SAndroid Build Coastguard Worker ResourceTable* table,
46*d57664e9SAndroid Build Coastguard Worker int options)
47*d57664e9SAndroid Build Coastguard Worker {
48*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> root = XMLNode::parse(target);
49*d57664e9SAndroid Build Coastguard Worker if (root == NULL) {
50*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
51*d57664e9SAndroid Build Coastguard Worker }
52*d57664e9SAndroid Build Coastguard Worker
53*d57664e9SAndroid Build Coastguard Worker return compileXmlFile(bundle, assets, resourceName, root, target, table, options);
54*d57664e9SAndroid Build Coastguard Worker }
55*d57664e9SAndroid Build Coastguard Worker
compileXmlFile(const Bundle * bundle,const sp<AaptAssets> & assets,const String16 & resourceName,const sp<AaptFile> & target,const sp<AaptFile> & outTarget,ResourceTable * table,int options)56*d57664e9SAndroid Build Coastguard Worker status_t compileXmlFile(const Bundle* bundle,
57*d57664e9SAndroid Build Coastguard Worker const sp<AaptAssets>& assets,
58*d57664e9SAndroid Build Coastguard Worker const String16& resourceName,
59*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target,
60*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& outTarget,
61*d57664e9SAndroid Build Coastguard Worker ResourceTable* table,
62*d57664e9SAndroid Build Coastguard Worker int options)
63*d57664e9SAndroid Build Coastguard Worker {
64*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> root = XMLNode::parse(target);
65*d57664e9SAndroid Build Coastguard Worker if (root == NULL) {
66*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
67*d57664e9SAndroid Build Coastguard Worker }
68*d57664e9SAndroid Build Coastguard Worker
69*d57664e9SAndroid Build Coastguard Worker return compileXmlFile(bundle, assets, resourceName, root, outTarget, table, options);
70*d57664e9SAndroid Build Coastguard Worker }
71*d57664e9SAndroid Build Coastguard Worker
compileXmlFile(const Bundle * bundle,const sp<AaptAssets> & assets,const String16 & resourceName,const sp<XMLNode> & root,const sp<AaptFile> & target,ResourceTable * table,int options)72*d57664e9SAndroid Build Coastguard Worker status_t compileXmlFile(const Bundle* bundle,
73*d57664e9SAndroid Build Coastguard Worker const sp<AaptAssets>& assets,
74*d57664e9SAndroid Build Coastguard Worker const String16& resourceName,
75*d57664e9SAndroid Build Coastguard Worker const sp<XMLNode>& root,
76*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target,
77*d57664e9SAndroid Build Coastguard Worker ResourceTable* table,
78*d57664e9SAndroid Build Coastguard Worker int options)
79*d57664e9SAndroid Build Coastguard Worker {
80*d57664e9SAndroid Build Coastguard Worker if (table->versionForCompat(bundle, resourceName, target, root)) {
81*d57664e9SAndroid Build Coastguard Worker // The file was versioned, so stop processing here.
82*d57664e9SAndroid Build Coastguard Worker // The resource entry has already been removed and the new one added.
83*d57664e9SAndroid Build Coastguard Worker // Remove the assets entry.
84*d57664e9SAndroid Build Coastguard Worker sp<AaptDir> resDir = assets->getDirs().valueFor(String8("res"));
85*d57664e9SAndroid Build Coastguard Worker sp<AaptDir> dir = resDir->getDirs().valueFor(target->getGroupEntry().toDirName(
86*d57664e9SAndroid Build Coastguard Worker target->getResourceType()));
87*d57664e9SAndroid Build Coastguard Worker dir->removeFile(getPathLeaf(target->getPath()));
88*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
89*d57664e9SAndroid Build Coastguard Worker }
90*d57664e9SAndroid Build Coastguard Worker
91*d57664e9SAndroid Build Coastguard Worker if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
92*d57664e9SAndroid Build Coastguard Worker root->removeWhitespace(true, NULL);
93*d57664e9SAndroid Build Coastguard Worker } else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
94*d57664e9SAndroid Build Coastguard Worker root->removeWhitespace(false, NULL);
95*d57664e9SAndroid Build Coastguard Worker }
96*d57664e9SAndroid Build Coastguard Worker
97*d57664e9SAndroid Build Coastguard Worker if ((options&XML_COMPILE_UTF8) != 0) {
98*d57664e9SAndroid Build Coastguard Worker root->setUTF8(true);
99*d57664e9SAndroid Build Coastguard Worker }
100*d57664e9SAndroid Build Coastguard Worker
101*d57664e9SAndroid Build Coastguard Worker if (table->processBundleFormat(bundle, resourceName, target, root) != NO_ERROR) {
102*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker
105*d57664e9SAndroid Build Coastguard Worker bool hasErrors = false;
106*d57664e9SAndroid Build Coastguard Worker if ((options&XML_COMPILE_ASSIGN_ATTRIBUTE_IDS) != 0) {
107*d57664e9SAndroid Build Coastguard Worker status_t err = root->assignResourceIds(assets, table);
108*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
109*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
110*d57664e9SAndroid Build Coastguard Worker }
111*d57664e9SAndroid Build Coastguard Worker }
112*d57664e9SAndroid Build Coastguard Worker
113*d57664e9SAndroid Build Coastguard Worker if ((options&XML_COMPILE_PARSE_VALUES) != 0) {
114*d57664e9SAndroid Build Coastguard Worker status_t err = root->parseValues(assets, table);
115*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
116*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
117*d57664e9SAndroid Build Coastguard Worker }
118*d57664e9SAndroid Build Coastguard Worker }
119*d57664e9SAndroid Build Coastguard Worker
120*d57664e9SAndroid Build Coastguard Worker if (hasErrors) {
121*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
122*d57664e9SAndroid Build Coastguard Worker }
123*d57664e9SAndroid Build Coastguard Worker
124*d57664e9SAndroid Build Coastguard Worker if (table->modifyForCompat(bundle, resourceName, target, root) != NO_ERROR) {
125*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
126*d57664e9SAndroid Build Coastguard Worker }
127*d57664e9SAndroid Build Coastguard Worker
128*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
129*d57664e9SAndroid Build Coastguard Worker printf("Input XML Resource:\n");
130*d57664e9SAndroid Build Coastguard Worker root->print();
131*d57664e9SAndroid Build Coastguard Worker }
132*d57664e9SAndroid Build Coastguard Worker status_t err = root->flatten(target,
133*d57664e9SAndroid Build Coastguard Worker (options&XML_COMPILE_STRIP_COMMENTS) != 0,
134*d57664e9SAndroid Build Coastguard Worker (options&XML_COMPILE_STRIP_RAW_VALUES) != 0);
135*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
136*d57664e9SAndroid Build Coastguard Worker return err;
137*d57664e9SAndroid Build Coastguard Worker }
138*d57664e9SAndroid Build Coastguard Worker
139*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
140*d57664e9SAndroid Build Coastguard Worker printf("Output XML Resource:\n");
141*d57664e9SAndroid Build Coastguard Worker ResXMLTree tree;
142*d57664e9SAndroid Build Coastguard Worker tree.setTo(target->getData(), target->getSize());
143*d57664e9SAndroid Build Coastguard Worker printXMLBlock(&tree);
144*d57664e9SAndroid Build Coastguard Worker }
145*d57664e9SAndroid Build Coastguard Worker
146*d57664e9SAndroid Build Coastguard Worker target->setCompressionMethod(ZipEntry::kCompressDeflated);
147*d57664e9SAndroid Build Coastguard Worker
148*d57664e9SAndroid Build Coastguard Worker return err;
149*d57664e9SAndroid Build Coastguard Worker }
150*d57664e9SAndroid Build Coastguard Worker
151*d57664e9SAndroid Build Coastguard Worker struct flag_entry
152*d57664e9SAndroid Build Coastguard Worker {
153*d57664e9SAndroid Build Coastguard Worker const char16_t* name;
154*d57664e9SAndroid Build Coastguard Worker size_t nameLen;
155*d57664e9SAndroid Build Coastguard Worker uint32_t value;
156*d57664e9SAndroid Build Coastguard Worker const char* description;
157*d57664e9SAndroid Build Coastguard Worker };
158*d57664e9SAndroid Build Coastguard Worker
159*d57664e9SAndroid Build Coastguard Worker static const char16_t referenceArray[] =
160*d57664e9SAndroid Build Coastguard Worker { 'r', 'e', 'f', 'e', 'r', 'e', 'n', 'c', 'e' };
161*d57664e9SAndroid Build Coastguard Worker static const char16_t stringArray[] =
162*d57664e9SAndroid Build Coastguard Worker { 's', 't', 'r', 'i', 'n', 'g' };
163*d57664e9SAndroid Build Coastguard Worker static const char16_t integerArray[] =
164*d57664e9SAndroid Build Coastguard Worker { 'i', 'n', 't', 'e', 'g', 'e', 'r' };
165*d57664e9SAndroid Build Coastguard Worker static const char16_t booleanArray[] =
166*d57664e9SAndroid Build Coastguard Worker { 'b', 'o', 'o', 'l', 'e', 'a', 'n' };
167*d57664e9SAndroid Build Coastguard Worker static const char16_t colorArray[] =
168*d57664e9SAndroid Build Coastguard Worker { 'c', 'o', 'l', 'o', 'r' };
169*d57664e9SAndroid Build Coastguard Worker static const char16_t floatArray[] =
170*d57664e9SAndroid Build Coastguard Worker { 'f', 'l', 'o', 'a', 't' };
171*d57664e9SAndroid Build Coastguard Worker static const char16_t dimensionArray[] =
172*d57664e9SAndroid Build Coastguard Worker { 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n' };
173*d57664e9SAndroid Build Coastguard Worker static const char16_t fractionArray[] =
174*d57664e9SAndroid Build Coastguard Worker { 'f', 'r', 'a', 'c', 't', 'i', 'o', 'n' };
175*d57664e9SAndroid Build Coastguard Worker static const char16_t enumArray[] =
176*d57664e9SAndroid Build Coastguard Worker { 'e', 'n', 'u', 'm' };
177*d57664e9SAndroid Build Coastguard Worker static const char16_t flagsArray[] =
178*d57664e9SAndroid Build Coastguard Worker { 'f', 'l', 'a', 'g', 's' };
179*d57664e9SAndroid Build Coastguard Worker
180*d57664e9SAndroid Build Coastguard Worker static const flag_entry gFormatFlags[] = {
181*d57664e9SAndroid Build Coastguard Worker { referenceArray, sizeof(referenceArray)/2, ResTable_map::TYPE_REFERENCE,
182*d57664e9SAndroid Build Coastguard Worker "a reference to another resource, in the form \"<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>\"\n"
183*d57664e9SAndroid Build Coastguard Worker "or to a theme attribute in the form \"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\"."},
184*d57664e9SAndroid Build Coastguard Worker { stringArray, sizeof(stringArray)/2, ResTable_map::TYPE_STRING,
185*d57664e9SAndroid Build Coastguard Worker "a string value, using '\\\\;' to escape characters such as '\\\\n' or '\\\\uxxxx' for a unicode character." },
186*d57664e9SAndroid Build Coastguard Worker { integerArray, sizeof(integerArray)/2, ResTable_map::TYPE_INTEGER,
187*d57664e9SAndroid Build Coastguard Worker "an integer value, such as \"<code>100</code>\"." },
188*d57664e9SAndroid Build Coastguard Worker { booleanArray, sizeof(booleanArray)/2, ResTable_map::TYPE_BOOLEAN,
189*d57664e9SAndroid Build Coastguard Worker "a boolean value, either \"<code>true</code>\" or \"<code>false</code>\"." },
190*d57664e9SAndroid Build Coastguard Worker { colorArray, sizeof(colorArray)/2, ResTable_map::TYPE_COLOR,
191*d57664e9SAndroid Build Coastguard Worker "a color value, in the form of \"<code>#<i>rgb</i></code>\", \"<code>#<i>argb</i></code>\",\n"
192*d57664e9SAndroid Build Coastguard Worker "\"<code>#<i>rrggbb</i></code>\", or \"<code>#<i>aarrggbb</i></code>\"." },
193*d57664e9SAndroid Build Coastguard Worker { floatArray, sizeof(floatArray)/2, ResTable_map::TYPE_FLOAT,
194*d57664e9SAndroid Build Coastguard Worker "a floating point value, such as \"<code>1.2</code>\"."},
195*d57664e9SAndroid Build Coastguard Worker { dimensionArray, sizeof(dimensionArray)/2, ResTable_map::TYPE_DIMENSION,
196*d57664e9SAndroid Build Coastguard Worker "a dimension value, which is a floating point number appended with a unit such as \"<code>14.5sp</code>\".\n"
197*d57664e9SAndroid Build Coastguard Worker "Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\n"
198*d57664e9SAndroid Build Coastguard Worker "in (inches), mm (millimeters)." },
199*d57664e9SAndroid Build Coastguard Worker { fractionArray, sizeof(fractionArray)/2, ResTable_map::TYPE_FRACTION,
200*d57664e9SAndroid Build Coastguard Worker "a fractional value, which is a floating point number appended with either % or %p, such as \"<code>14.5%</code>\".\n"
201*d57664e9SAndroid Build Coastguard Worker "The % suffix always means a percentage of the base size; the optional %p suffix provides a size relative to\n"
202*d57664e9SAndroid Build Coastguard Worker "some parent container." },
203*d57664e9SAndroid Build Coastguard Worker { enumArray, sizeof(enumArray)/2, ResTable_map::TYPE_ENUM, NULL },
204*d57664e9SAndroid Build Coastguard Worker { flagsArray, sizeof(flagsArray)/2, ResTable_map::TYPE_FLAGS, NULL },
205*d57664e9SAndroid Build Coastguard Worker { NULL, 0, 0, NULL }
206*d57664e9SAndroid Build Coastguard Worker };
207*d57664e9SAndroid Build Coastguard Worker
208*d57664e9SAndroid Build Coastguard Worker static const char16_t suggestedArray[] = { 's', 'u', 'g', 'g', 'e', 's', 't', 'e', 'd' };
209*d57664e9SAndroid Build Coastguard Worker
210*d57664e9SAndroid Build Coastguard Worker static const flag_entry l10nRequiredFlags[] = {
211*d57664e9SAndroid Build Coastguard Worker { suggestedArray, sizeof(suggestedArray)/2, ResTable_map::L10N_SUGGESTED, NULL },
212*d57664e9SAndroid Build Coastguard Worker { NULL, 0, 0, NULL }
213*d57664e9SAndroid Build Coastguard Worker };
214*d57664e9SAndroid Build Coastguard Worker
215*d57664e9SAndroid Build Coastguard Worker static const char16_t nulStr[] = { 0 };
216*d57664e9SAndroid Build Coastguard Worker
parse_flags(const char16_t * str,size_t len,const flag_entry * flags,bool * outError=NULL)217*d57664e9SAndroid Build Coastguard Worker static uint32_t parse_flags(const char16_t* str, size_t len,
218*d57664e9SAndroid Build Coastguard Worker const flag_entry* flags, bool* outError = NULL)
219*d57664e9SAndroid Build Coastguard Worker {
220*d57664e9SAndroid Build Coastguard Worker while (len > 0 && isspace(*str)) {
221*d57664e9SAndroid Build Coastguard Worker str++;
222*d57664e9SAndroid Build Coastguard Worker len--;
223*d57664e9SAndroid Build Coastguard Worker }
224*d57664e9SAndroid Build Coastguard Worker while (len > 0 && isspace(str[len-1])) {
225*d57664e9SAndroid Build Coastguard Worker len--;
226*d57664e9SAndroid Build Coastguard Worker }
227*d57664e9SAndroid Build Coastguard Worker
228*d57664e9SAndroid Build Coastguard Worker const char16_t* const end = str + len;
229*d57664e9SAndroid Build Coastguard Worker uint32_t value = 0;
230*d57664e9SAndroid Build Coastguard Worker
231*d57664e9SAndroid Build Coastguard Worker while (str < end) {
232*d57664e9SAndroid Build Coastguard Worker const char16_t* div = str;
233*d57664e9SAndroid Build Coastguard Worker while (div < end && *div != '|') {
234*d57664e9SAndroid Build Coastguard Worker div++;
235*d57664e9SAndroid Build Coastguard Worker }
236*d57664e9SAndroid Build Coastguard Worker
237*d57664e9SAndroid Build Coastguard Worker const flag_entry* cur = flags;
238*d57664e9SAndroid Build Coastguard Worker while (cur->name) {
239*d57664e9SAndroid Build Coastguard Worker if (strzcmp16(cur->name, cur->nameLen, str, div-str) == 0) {
240*d57664e9SAndroid Build Coastguard Worker value |= cur->value;
241*d57664e9SAndroid Build Coastguard Worker break;
242*d57664e9SAndroid Build Coastguard Worker }
243*d57664e9SAndroid Build Coastguard Worker cur++;
244*d57664e9SAndroid Build Coastguard Worker }
245*d57664e9SAndroid Build Coastguard Worker
246*d57664e9SAndroid Build Coastguard Worker if (!cur->name) {
247*d57664e9SAndroid Build Coastguard Worker if (outError) *outError = true;
248*d57664e9SAndroid Build Coastguard Worker return 0;
249*d57664e9SAndroid Build Coastguard Worker }
250*d57664e9SAndroid Build Coastguard Worker
251*d57664e9SAndroid Build Coastguard Worker str = div < end ? div+1 : div;
252*d57664e9SAndroid Build Coastguard Worker }
253*d57664e9SAndroid Build Coastguard Worker
254*d57664e9SAndroid Build Coastguard Worker if (outError) *outError = false;
255*d57664e9SAndroid Build Coastguard Worker return value;
256*d57664e9SAndroid Build Coastguard Worker }
257*d57664e9SAndroid Build Coastguard Worker
mayOrMust(int type,int flags)258*d57664e9SAndroid Build Coastguard Worker static String16 mayOrMust(int type, int flags)
259*d57664e9SAndroid Build Coastguard Worker {
260*d57664e9SAndroid Build Coastguard Worker if ((type&(~flags)) == 0) {
261*d57664e9SAndroid Build Coastguard Worker return String16("<p>Must");
262*d57664e9SAndroid Build Coastguard Worker }
263*d57664e9SAndroid Build Coastguard Worker
264*d57664e9SAndroid Build Coastguard Worker return String16("<p>May");
265*d57664e9SAndroid Build Coastguard Worker }
266*d57664e9SAndroid Build Coastguard Worker
appendTypeInfo(ResourceTable * outTable,const String16 & pkg,const String16 & typeName,const String16 & ident,int type,const flag_entry * flags)267*d57664e9SAndroid Build Coastguard Worker static void appendTypeInfo(ResourceTable* outTable, const String16& pkg,
268*d57664e9SAndroid Build Coastguard Worker const String16& typeName, const String16& ident, int type,
269*d57664e9SAndroid Build Coastguard Worker const flag_entry* flags)
270*d57664e9SAndroid Build Coastguard Worker {
271*d57664e9SAndroid Build Coastguard Worker bool hadType = false;
272*d57664e9SAndroid Build Coastguard Worker while (flags->name) {
273*d57664e9SAndroid Build Coastguard Worker if ((type&flags->value) != 0 && flags->description != NULL) {
274*d57664e9SAndroid Build Coastguard Worker String16 fullMsg(mayOrMust(type, flags->value));
275*d57664e9SAndroid Build Coastguard Worker fullMsg.append(String16(" be "));
276*d57664e9SAndroid Build Coastguard Worker fullMsg.append(String16(flags->description));
277*d57664e9SAndroid Build Coastguard Worker outTable->appendTypeComment(pkg, typeName, ident, fullMsg);
278*d57664e9SAndroid Build Coastguard Worker hadType = true;
279*d57664e9SAndroid Build Coastguard Worker }
280*d57664e9SAndroid Build Coastguard Worker flags++;
281*d57664e9SAndroid Build Coastguard Worker }
282*d57664e9SAndroid Build Coastguard Worker if (hadType && (type&ResTable_map::TYPE_REFERENCE) == 0) {
283*d57664e9SAndroid Build Coastguard Worker outTable->appendTypeComment(pkg, typeName, ident,
284*d57664e9SAndroid Build Coastguard Worker String16("<p>This may also be a reference to a resource (in the form\n"
285*d57664e9SAndroid Build Coastguard Worker "\"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>\") or\n"
286*d57664e9SAndroid Build Coastguard Worker "theme attribute (in the form\n"
287*d57664e9SAndroid Build Coastguard Worker "\"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>\")\n"
288*d57664e9SAndroid Build Coastguard Worker "containing a value of this type."));
289*d57664e9SAndroid Build Coastguard Worker }
290*d57664e9SAndroid Build Coastguard Worker }
291*d57664e9SAndroid Build Coastguard Worker
292*d57664e9SAndroid Build Coastguard Worker struct PendingAttribute
293*d57664e9SAndroid Build Coastguard Worker {
294*d57664e9SAndroid Build Coastguard Worker const String16 myPackage;
295*d57664e9SAndroid Build Coastguard Worker const SourcePos sourcePos;
296*d57664e9SAndroid Build Coastguard Worker const bool appendComment;
297*d57664e9SAndroid Build Coastguard Worker int32_t type;
298*d57664e9SAndroid Build Coastguard Worker String16 ident;
299*d57664e9SAndroid Build Coastguard Worker String16 comment;
300*d57664e9SAndroid Build Coastguard Worker bool hasErrors;
301*d57664e9SAndroid Build Coastguard Worker bool added;
302*d57664e9SAndroid Build Coastguard Worker
PendingAttributePendingAttribute303*d57664e9SAndroid Build Coastguard Worker PendingAttribute(String16 _package, const sp<AaptFile>& in,
304*d57664e9SAndroid Build Coastguard Worker ResXMLTree& block, bool _appendComment)
305*d57664e9SAndroid Build Coastguard Worker : myPackage(_package)
306*d57664e9SAndroid Build Coastguard Worker , sourcePos(in->getPrintableSource(), block.getLineNumber())
307*d57664e9SAndroid Build Coastguard Worker , appendComment(_appendComment)
308*d57664e9SAndroid Build Coastguard Worker , type(ResTable_map::TYPE_ANY)
309*d57664e9SAndroid Build Coastguard Worker , hasErrors(false)
310*d57664e9SAndroid Build Coastguard Worker , added(false)
311*d57664e9SAndroid Build Coastguard Worker {
312*d57664e9SAndroid Build Coastguard Worker }
313*d57664e9SAndroid Build Coastguard Worker
createIfNeededPendingAttribute314*d57664e9SAndroid Build Coastguard Worker status_t createIfNeeded(ResourceTable* outTable)
315*d57664e9SAndroid Build Coastguard Worker {
316*d57664e9SAndroid Build Coastguard Worker if (added || hasErrors) {
317*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
318*d57664e9SAndroid Build Coastguard Worker }
319*d57664e9SAndroid Build Coastguard Worker added = true;
320*d57664e9SAndroid Build Coastguard Worker
321*d57664e9SAndroid Build Coastguard Worker if (!outTable->makeAttribute(myPackage, ident, sourcePos, type, comment, appendComment)) {
322*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
323*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
324*d57664e9SAndroid Build Coastguard Worker }
325*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
326*d57664e9SAndroid Build Coastguard Worker }
327*d57664e9SAndroid Build Coastguard Worker };
328*d57664e9SAndroid Build Coastguard Worker
compileAttribute(const sp<AaptFile> & in,ResXMLTree & block,const String16 & myPackage,ResourceTable * outTable,String16 * outIdent=NULL,bool inStyleable=false)329*d57664e9SAndroid Build Coastguard Worker static status_t compileAttribute(const sp<AaptFile>& in,
330*d57664e9SAndroid Build Coastguard Worker ResXMLTree& block,
331*d57664e9SAndroid Build Coastguard Worker const String16& myPackage,
332*d57664e9SAndroid Build Coastguard Worker ResourceTable* outTable,
333*d57664e9SAndroid Build Coastguard Worker String16* outIdent = NULL,
334*d57664e9SAndroid Build Coastguard Worker bool inStyleable = false)
335*d57664e9SAndroid Build Coastguard Worker {
336*d57664e9SAndroid Build Coastguard Worker PendingAttribute attr(myPackage, in, block, inStyleable);
337*d57664e9SAndroid Build Coastguard Worker
338*d57664e9SAndroid Build Coastguard Worker const String16 attr16("attr");
339*d57664e9SAndroid Build Coastguard Worker const String16 id16("id");
340*d57664e9SAndroid Build Coastguard Worker
341*d57664e9SAndroid Build Coastguard Worker // Attribute type constants.
342*d57664e9SAndroid Build Coastguard Worker const String16 enum16("enum");
343*d57664e9SAndroid Build Coastguard Worker const String16 flag16("flag");
344*d57664e9SAndroid Build Coastguard Worker
345*d57664e9SAndroid Build Coastguard Worker ResXMLTree::event_code_t code;
346*d57664e9SAndroid Build Coastguard Worker size_t len;
347*d57664e9SAndroid Build Coastguard Worker status_t err;
348*d57664e9SAndroid Build Coastguard Worker
349*d57664e9SAndroid Build Coastguard Worker ssize_t identIdx = block.indexOfAttribute(NULL, "name");
350*d57664e9SAndroid Build Coastguard Worker if (identIdx >= 0) {
351*d57664e9SAndroid Build Coastguard Worker attr.ident = String16(block.getAttributeStringValue(identIdx, &len));
352*d57664e9SAndroid Build Coastguard Worker if (outIdent) {
353*d57664e9SAndroid Build Coastguard Worker *outIdent = attr.ident;
354*d57664e9SAndroid Build Coastguard Worker }
355*d57664e9SAndroid Build Coastguard Worker } else {
356*d57664e9SAndroid Build Coastguard Worker attr.sourcePos.error("A 'name' attribute is required for <attr>\n");
357*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
358*d57664e9SAndroid Build Coastguard Worker }
359*d57664e9SAndroid Build Coastguard Worker
360*d57664e9SAndroid Build Coastguard Worker attr.comment = String16(
361*d57664e9SAndroid Build Coastguard Worker block.getComment(&len) ? block.getComment(&len) : nulStr);
362*d57664e9SAndroid Build Coastguard Worker
363*d57664e9SAndroid Build Coastguard Worker ssize_t typeIdx = block.indexOfAttribute(NULL, "format");
364*d57664e9SAndroid Build Coastguard Worker if (typeIdx >= 0) {
365*d57664e9SAndroid Build Coastguard Worker String16 typeStr = String16(block.getAttributeStringValue(typeIdx, &len));
366*d57664e9SAndroid Build Coastguard Worker attr.type = parse_flags(typeStr.c_str(), typeStr.size(), gFormatFlags);
367*d57664e9SAndroid Build Coastguard Worker if (attr.type == 0) {
368*d57664e9SAndroid Build Coastguard Worker attr.sourcePos.error("Tag <attr> 'format' attribute value \"%s\" not valid\n",
369*d57664e9SAndroid Build Coastguard Worker String8(typeStr).c_str());
370*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
371*d57664e9SAndroid Build Coastguard Worker }
372*d57664e9SAndroid Build Coastguard Worker attr.createIfNeeded(outTable);
373*d57664e9SAndroid Build Coastguard Worker } else if (!inStyleable) {
374*d57664e9SAndroid Build Coastguard Worker // Attribute definitions outside of styleables always define the
375*d57664e9SAndroid Build Coastguard Worker // attribute as a generic value.
376*d57664e9SAndroid Build Coastguard Worker attr.createIfNeeded(outTable);
377*d57664e9SAndroid Build Coastguard Worker }
378*d57664e9SAndroid Build Coastguard Worker
379*d57664e9SAndroid Build Coastguard Worker //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).c_str(), attr.type);
380*d57664e9SAndroid Build Coastguard Worker
381*d57664e9SAndroid Build Coastguard Worker ssize_t minIdx = block.indexOfAttribute(NULL, "min");
382*d57664e9SAndroid Build Coastguard Worker if (minIdx >= 0) {
383*d57664e9SAndroid Build Coastguard Worker String16 val = String16(block.getAttributeStringValue(minIdx, &len));
384*d57664e9SAndroid Build Coastguard Worker if (!ResTable::stringToInt(val.c_str(), val.size(), NULL)) {
385*d57664e9SAndroid Build Coastguard Worker attr.sourcePos.error("Tag <attr> 'min' attribute must be a number, not \"%s\"\n",
386*d57664e9SAndroid Build Coastguard Worker String8(val).c_str());
387*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
388*d57664e9SAndroid Build Coastguard Worker }
389*d57664e9SAndroid Build Coastguard Worker attr.createIfNeeded(outTable);
390*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors) {
391*d57664e9SAndroid Build Coastguard Worker err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
392*d57664e9SAndroid Build Coastguard Worker String16(""), String16("^min"), String16(val), NULL, NULL);
393*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
394*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
395*d57664e9SAndroid Build Coastguard Worker }
396*d57664e9SAndroid Build Coastguard Worker }
397*d57664e9SAndroid Build Coastguard Worker }
398*d57664e9SAndroid Build Coastguard Worker
399*d57664e9SAndroid Build Coastguard Worker ssize_t maxIdx = block.indexOfAttribute(NULL, "max");
400*d57664e9SAndroid Build Coastguard Worker if (maxIdx >= 0) {
401*d57664e9SAndroid Build Coastguard Worker String16 val = String16(block.getAttributeStringValue(maxIdx, &len));
402*d57664e9SAndroid Build Coastguard Worker if (!ResTable::stringToInt(val.c_str(), val.size(), NULL)) {
403*d57664e9SAndroid Build Coastguard Worker attr.sourcePos.error("Tag <attr> 'max' attribute must be a number, not \"%s\"\n",
404*d57664e9SAndroid Build Coastguard Worker String8(val).c_str());
405*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
406*d57664e9SAndroid Build Coastguard Worker }
407*d57664e9SAndroid Build Coastguard Worker attr.createIfNeeded(outTable);
408*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors) {
409*d57664e9SAndroid Build Coastguard Worker err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
410*d57664e9SAndroid Build Coastguard Worker String16(""), String16("^max"), String16(val), NULL, NULL);
411*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
412*d57664e9SAndroid Build Coastguard Worker }
413*d57664e9SAndroid Build Coastguard Worker }
414*d57664e9SAndroid Build Coastguard Worker
415*d57664e9SAndroid Build Coastguard Worker if ((minIdx >= 0 || maxIdx >= 0) && (attr.type&ResTable_map::TYPE_INTEGER) == 0) {
416*d57664e9SAndroid Build Coastguard Worker attr.sourcePos.error("Tag <attr> must have format=integer attribute if using max or min\n");
417*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
418*d57664e9SAndroid Build Coastguard Worker }
419*d57664e9SAndroid Build Coastguard Worker
420*d57664e9SAndroid Build Coastguard Worker ssize_t l10nIdx = block.indexOfAttribute(NULL, "localization");
421*d57664e9SAndroid Build Coastguard Worker if (l10nIdx >= 0) {
422*d57664e9SAndroid Build Coastguard Worker const char16_t* str = block.getAttributeStringValue(l10nIdx, &len);
423*d57664e9SAndroid Build Coastguard Worker bool error;
424*d57664e9SAndroid Build Coastguard Worker uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error);
425*d57664e9SAndroid Build Coastguard Worker if (error) {
426*d57664e9SAndroid Build Coastguard Worker attr.sourcePos.error("Tag <attr> 'localization' attribute value \"%s\" not valid\n",
427*d57664e9SAndroid Build Coastguard Worker String8(str).c_str());
428*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
429*d57664e9SAndroid Build Coastguard Worker }
430*d57664e9SAndroid Build Coastguard Worker attr.createIfNeeded(outTable);
431*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors) {
432*d57664e9SAndroid Build Coastguard Worker char buf[11];
433*d57664e9SAndroid Build Coastguard Worker sprintf(buf, "%d", l10n_required);
434*d57664e9SAndroid Build Coastguard Worker err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
435*d57664e9SAndroid Build Coastguard Worker String16(""), String16("^l10n"), String16(buf), NULL, NULL);
436*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
437*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
438*d57664e9SAndroid Build Coastguard Worker }
439*d57664e9SAndroid Build Coastguard Worker }
440*d57664e9SAndroid Build Coastguard Worker }
441*d57664e9SAndroid Build Coastguard Worker
442*d57664e9SAndroid Build Coastguard Worker String16 enumOrFlagsComment;
443*d57664e9SAndroid Build Coastguard Worker
444*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
445*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::START_TAG) {
446*d57664e9SAndroid Build Coastguard Worker uint32_t localType = 0;
447*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), enum16.c_str()) == 0) {
448*d57664e9SAndroid Build Coastguard Worker localType = ResTable_map::TYPE_ENUM;
449*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), flag16.c_str()) == 0) {
450*d57664e9SAndroid Build Coastguard Worker localType = ResTable_map::TYPE_FLAGS;
451*d57664e9SAndroid Build Coastguard Worker } else {
452*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
453*d57664e9SAndroid Build Coastguard Worker .error("Tag <%s> can not appear inside <attr>, only <enum> or <flag>\n",
454*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str());
455*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
456*d57664e9SAndroid Build Coastguard Worker }
457*d57664e9SAndroid Build Coastguard Worker
458*d57664e9SAndroid Build Coastguard Worker attr.createIfNeeded(outTable);
459*d57664e9SAndroid Build Coastguard Worker
460*d57664e9SAndroid Build Coastguard Worker if (attr.type == ResTable_map::TYPE_ANY) {
461*d57664e9SAndroid Build Coastguard Worker // No type was explicitly stated, so supplying enum tags
462*d57664e9SAndroid Build Coastguard Worker // implicitly creates an enum or flag.
463*d57664e9SAndroid Build Coastguard Worker attr.type = 0;
464*d57664e9SAndroid Build Coastguard Worker }
465*d57664e9SAndroid Build Coastguard Worker
466*d57664e9SAndroid Build Coastguard Worker if ((attr.type&(ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)) == 0) {
467*d57664e9SAndroid Build Coastguard Worker // Wasn't originally specified as an enum, so update its type.
468*d57664e9SAndroid Build Coastguard Worker attr.type |= localType;
469*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors) {
470*d57664e9SAndroid Build Coastguard Worker char numberStr[16];
471*d57664e9SAndroid Build Coastguard Worker sprintf(numberStr, "%d", attr.type);
472*d57664e9SAndroid Build Coastguard Worker err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
473*d57664e9SAndroid Build Coastguard Worker myPackage, attr16, attr.ident, String16(""),
474*d57664e9SAndroid Build Coastguard Worker String16("^type"), String16(numberStr), NULL, NULL, true);
475*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
476*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
477*d57664e9SAndroid Build Coastguard Worker }
478*d57664e9SAndroid Build Coastguard Worker }
479*d57664e9SAndroid Build Coastguard Worker } else if ((uint32_t)(attr.type&(ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS)) != localType) {
480*d57664e9SAndroid Build Coastguard Worker if (localType == ResTable_map::TYPE_ENUM) {
481*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
482*d57664e9SAndroid Build Coastguard Worker .error("<enum> attribute can not be used inside a flags format\n");
483*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
484*d57664e9SAndroid Build Coastguard Worker } else {
485*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
486*d57664e9SAndroid Build Coastguard Worker .error("<flag> attribute can not be used inside a enum format\n");
487*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
488*d57664e9SAndroid Build Coastguard Worker }
489*d57664e9SAndroid Build Coastguard Worker }
490*d57664e9SAndroid Build Coastguard Worker
491*d57664e9SAndroid Build Coastguard Worker String16 itemIdent;
492*d57664e9SAndroid Build Coastguard Worker ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "name");
493*d57664e9SAndroid Build Coastguard Worker if (itemIdentIdx >= 0) {
494*d57664e9SAndroid Build Coastguard Worker itemIdent = String16(block.getAttributeStringValue(itemIdentIdx, &len));
495*d57664e9SAndroid Build Coastguard Worker } else {
496*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
497*d57664e9SAndroid Build Coastguard Worker .error("A 'name' attribute is required for <enum> or <flag>\n");
498*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
499*d57664e9SAndroid Build Coastguard Worker }
500*d57664e9SAndroid Build Coastguard Worker
501*d57664e9SAndroid Build Coastguard Worker String16 value;
502*d57664e9SAndroid Build Coastguard Worker ssize_t valueIdx = block.indexOfAttribute(NULL, "value");
503*d57664e9SAndroid Build Coastguard Worker if (valueIdx >= 0) {
504*d57664e9SAndroid Build Coastguard Worker value = String16(block.getAttributeStringValue(valueIdx, &len));
505*d57664e9SAndroid Build Coastguard Worker } else {
506*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
507*d57664e9SAndroid Build Coastguard Worker .error("A 'value' attribute is required for <enum> or <flag>\n");
508*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
509*d57664e9SAndroid Build Coastguard Worker }
510*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors && !ResTable::stringToInt(value.c_str(), value.size(), NULL)) {
511*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
512*d57664e9SAndroid Build Coastguard Worker .error("Tag <enum> or <flag> 'value' attribute must be a number,"
513*d57664e9SAndroid Build Coastguard Worker " not \"%s\"\n",
514*d57664e9SAndroid Build Coastguard Worker String8(value).c_str());
515*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
516*d57664e9SAndroid Build Coastguard Worker }
517*d57664e9SAndroid Build Coastguard Worker
518*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors) {
519*d57664e9SAndroid Build Coastguard Worker if (enumOrFlagsComment.size() == 0) {
520*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(mayOrMust(attr.type,
521*d57664e9SAndroid Build Coastguard Worker ResTable_map::TYPE_ENUM|ResTable_map::TYPE_FLAGS));
522*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append((attr.type&ResTable_map::TYPE_ENUM)
523*d57664e9SAndroid Build Coastguard Worker ? String16(" be one of the following constant values.")
524*d57664e9SAndroid Build Coastguard Worker : String16(" be one or more (separated by '|') of the following constant values."));
525*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16("</p>\n<table>\n"
526*d57664e9SAndroid Build Coastguard Worker "<colgroup align=\"left\" />\n"
527*d57664e9SAndroid Build Coastguard Worker "<colgroup align=\"left\" />\n"
528*d57664e9SAndroid Build Coastguard Worker "<colgroup align=\"left\" />\n"
529*d57664e9SAndroid Build Coastguard Worker "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>"));
530*d57664e9SAndroid Build Coastguard Worker }
531*d57664e9SAndroid Build Coastguard Worker
532*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16("\n<tr><td><code>"));
533*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(itemIdent);
534*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16("</code></td><td>"));
535*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(value);
536*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16("</td><td>"));
537*d57664e9SAndroid Build Coastguard Worker if (block.getComment(&len)) {
538*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16(block.getComment(&len)));
539*d57664e9SAndroid Build Coastguard Worker }
540*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16("</td></tr>"));
541*d57664e9SAndroid Build Coastguard Worker
542*d57664e9SAndroid Build Coastguard Worker err = outTable->addBag(SourcePos(in->getPrintableSource(), block.getLineNumber()),
543*d57664e9SAndroid Build Coastguard Worker myPackage,
544*d57664e9SAndroid Build Coastguard Worker attr16, attr.ident, String16(""),
545*d57664e9SAndroid Build Coastguard Worker itemIdent, value, NULL, NULL, false, true);
546*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
547*d57664e9SAndroid Build Coastguard Worker attr.hasErrors = true;
548*d57664e9SAndroid Build Coastguard Worker }
549*d57664e9SAndroid Build Coastguard Worker }
550*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::END_TAG) {
551*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), attr16.c_str()) == 0) {
552*d57664e9SAndroid Build Coastguard Worker break;
553*d57664e9SAndroid Build Coastguard Worker }
554*d57664e9SAndroid Build Coastguard Worker if ((attr.type&ResTable_map::TYPE_ENUM) != 0) {
555*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), enum16.c_str()) != 0) {
556*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
557*d57664e9SAndroid Build Coastguard Worker .error("Found tag </%s> where </enum> is expected\n",
558*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str());
559*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
560*d57664e9SAndroid Build Coastguard Worker }
561*d57664e9SAndroid Build Coastguard Worker } else {
562*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), flag16.c_str()) != 0) {
563*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber())
564*d57664e9SAndroid Build Coastguard Worker .error("Found tag </%s> where </flag> is expected\n",
565*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str());
566*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
567*d57664e9SAndroid Build Coastguard Worker }
568*d57664e9SAndroid Build Coastguard Worker }
569*d57664e9SAndroid Build Coastguard Worker }
570*d57664e9SAndroid Build Coastguard Worker }
571*d57664e9SAndroid Build Coastguard Worker
572*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors && attr.added) {
573*d57664e9SAndroid Build Coastguard Worker appendTypeInfo(outTable, myPackage, attr16, attr.ident, attr.type, gFormatFlags);
574*d57664e9SAndroid Build Coastguard Worker }
575*d57664e9SAndroid Build Coastguard Worker
576*d57664e9SAndroid Build Coastguard Worker if (!attr.hasErrors && enumOrFlagsComment.size() > 0) {
577*d57664e9SAndroid Build Coastguard Worker enumOrFlagsComment.append(String16("\n</table>"));
578*d57664e9SAndroid Build Coastguard Worker outTable->appendTypeComment(myPackage, attr16, attr.ident, enumOrFlagsComment);
579*d57664e9SAndroid Build Coastguard Worker }
580*d57664e9SAndroid Build Coastguard Worker
581*d57664e9SAndroid Build Coastguard Worker
582*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
583*d57664e9SAndroid Build Coastguard Worker }
584*d57664e9SAndroid Build Coastguard Worker
localeIsDefined(const ResTable_config & config)585*d57664e9SAndroid Build Coastguard Worker bool localeIsDefined(const ResTable_config& config)
586*d57664e9SAndroid Build Coastguard Worker {
587*d57664e9SAndroid Build Coastguard Worker return config.locale == 0;
588*d57664e9SAndroid Build Coastguard Worker }
589*d57664e9SAndroid Build Coastguard Worker
parseAndAddBag(Bundle * bundle,const sp<AaptFile> & in,ResXMLTree * block,const ResTable_config & config,const String16 & myPackage,const String16 & curType,const String16 & ident,const String16 & parentIdent,const String16 & itemIdent,int32_t curFormat,bool isFormatted,const String16 &,PseudolocalizationMethod pseudolocalize,const bool overwrite,ResourceTable * outTable)590*d57664e9SAndroid Build Coastguard Worker status_t parseAndAddBag(Bundle* bundle,
591*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& in,
592*d57664e9SAndroid Build Coastguard Worker ResXMLTree* block,
593*d57664e9SAndroid Build Coastguard Worker const ResTable_config& config,
594*d57664e9SAndroid Build Coastguard Worker const String16& myPackage,
595*d57664e9SAndroid Build Coastguard Worker const String16& curType,
596*d57664e9SAndroid Build Coastguard Worker const String16& ident,
597*d57664e9SAndroid Build Coastguard Worker const String16& parentIdent,
598*d57664e9SAndroid Build Coastguard Worker const String16& itemIdent,
599*d57664e9SAndroid Build Coastguard Worker int32_t curFormat,
600*d57664e9SAndroid Build Coastguard Worker bool isFormatted,
601*d57664e9SAndroid Build Coastguard Worker const String16& /* product */,
602*d57664e9SAndroid Build Coastguard Worker PseudolocalizationMethod pseudolocalize,
603*d57664e9SAndroid Build Coastguard Worker const bool overwrite,
604*d57664e9SAndroid Build Coastguard Worker ResourceTable* outTable)
605*d57664e9SAndroid Build Coastguard Worker {
606*d57664e9SAndroid Build Coastguard Worker status_t err;
607*d57664e9SAndroid Build Coastguard Worker const String16 item16("item");
608*d57664e9SAndroid Build Coastguard Worker
609*d57664e9SAndroid Build Coastguard Worker String16 str;
610*d57664e9SAndroid Build Coastguard Worker Vector<StringPool::entry_style_span> spans;
611*d57664e9SAndroid Build Coastguard Worker err = parseStyledString(bundle, in->getPrintableSource().c_str(),
612*d57664e9SAndroid Build Coastguard Worker block, item16, &str, &spans, isFormatted,
613*d57664e9SAndroid Build Coastguard Worker pseudolocalize);
614*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
615*d57664e9SAndroid Build Coastguard Worker return err;
616*d57664e9SAndroid Build Coastguard Worker }
617*d57664e9SAndroid Build Coastguard Worker
618*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
619*d57664e9SAndroid Build Coastguard Worker printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d "
620*d57664e9SAndroid Build Coastguard Worker " pid=%s, bag=%s, id=%s: %s\n",
621*d57664e9SAndroid Build Coastguard Worker config.language[0], config.language[1],
622*d57664e9SAndroid Build Coastguard Worker config.country[0], config.country[1],
623*d57664e9SAndroid Build Coastguard Worker config.orientation, config.density,
624*d57664e9SAndroid Build Coastguard Worker String8(parentIdent).c_str(),
625*d57664e9SAndroid Build Coastguard Worker String8(ident).c_str(),
626*d57664e9SAndroid Build Coastguard Worker String8(itemIdent).c_str(),
627*d57664e9SAndroid Build Coastguard Worker String8(str).c_str());
628*d57664e9SAndroid Build Coastguard Worker }
629*d57664e9SAndroid Build Coastguard Worker
630*d57664e9SAndroid Build Coastguard Worker err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
631*d57664e9SAndroid Build Coastguard Worker myPackage, curType, ident, parentIdent, itemIdent, str,
632*d57664e9SAndroid Build Coastguard Worker &spans, &config, overwrite, false, curFormat);
633*d57664e9SAndroid Build Coastguard Worker return err;
634*d57664e9SAndroid Build Coastguard Worker }
635*d57664e9SAndroid Build Coastguard Worker
636*d57664e9SAndroid Build Coastguard Worker /*
637*d57664e9SAndroid Build Coastguard Worker * Returns true if needle is one of the elements in the comma-separated list
638*d57664e9SAndroid Build Coastguard Worker * haystack, false otherwise.
639*d57664e9SAndroid Build Coastguard Worker */
isInProductList(const String16 & needle,const String16 & haystack)640*d57664e9SAndroid Build Coastguard Worker bool isInProductList(const String16& needle, const String16& haystack) {
641*d57664e9SAndroid Build Coastguard Worker const char16_t *needle2 = needle.c_str();
642*d57664e9SAndroid Build Coastguard Worker const char16_t *haystack2 = haystack.c_str();
643*d57664e9SAndroid Build Coastguard Worker size_t needlesize = needle.size();
644*d57664e9SAndroid Build Coastguard Worker
645*d57664e9SAndroid Build Coastguard Worker while (*haystack2 != '\0') {
646*d57664e9SAndroid Build Coastguard Worker if (strncmp16(haystack2, needle2, needlesize) == 0) {
647*d57664e9SAndroid Build Coastguard Worker if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') {
648*d57664e9SAndroid Build Coastguard Worker return true;
649*d57664e9SAndroid Build Coastguard Worker }
650*d57664e9SAndroid Build Coastguard Worker }
651*d57664e9SAndroid Build Coastguard Worker
652*d57664e9SAndroid Build Coastguard Worker while (*haystack2 != '\0' && *haystack2 != ',') {
653*d57664e9SAndroid Build Coastguard Worker haystack2++;
654*d57664e9SAndroid Build Coastguard Worker }
655*d57664e9SAndroid Build Coastguard Worker if (*haystack2 == ',') {
656*d57664e9SAndroid Build Coastguard Worker haystack2++;
657*d57664e9SAndroid Build Coastguard Worker }
658*d57664e9SAndroid Build Coastguard Worker }
659*d57664e9SAndroid Build Coastguard Worker
660*d57664e9SAndroid Build Coastguard Worker return false;
661*d57664e9SAndroid Build Coastguard Worker }
662*d57664e9SAndroid Build Coastguard Worker
663*d57664e9SAndroid Build Coastguard Worker /*
664*d57664e9SAndroid Build Coastguard Worker * A simple container that holds a resource type and name. It is ordered first by type then
665*d57664e9SAndroid Build Coastguard Worker * by name.
666*d57664e9SAndroid Build Coastguard Worker */
667*d57664e9SAndroid Build Coastguard Worker struct type_ident_pair_t {
668*d57664e9SAndroid Build Coastguard Worker String16 type;
669*d57664e9SAndroid Build Coastguard Worker String16 ident;
670*d57664e9SAndroid Build Coastguard Worker
type_ident_pair_ttype_ident_pair_t671*d57664e9SAndroid Build Coastguard Worker type_ident_pair_t() { };
type_ident_pair_ttype_ident_pair_t672*d57664e9SAndroid Build Coastguard Worker type_ident_pair_t(const String16& t, const String16& i) : type(t), ident(i) { }
type_ident_pair_ttype_ident_pair_t673*d57664e9SAndroid Build Coastguard Worker type_ident_pair_t(const type_ident_pair_t& o) : type(o.type), ident(o.ident) { }
operator <type_ident_pair_t674*d57664e9SAndroid Build Coastguard Worker inline bool operator < (const type_ident_pair_t& o) const {
675*d57664e9SAndroid Build Coastguard Worker int cmp = compare_type(type, o.type);
676*d57664e9SAndroid Build Coastguard Worker if (cmp < 0) {
677*d57664e9SAndroid Build Coastguard Worker return true;
678*d57664e9SAndroid Build Coastguard Worker } else if (cmp > 0) {
679*d57664e9SAndroid Build Coastguard Worker return false;
680*d57664e9SAndroid Build Coastguard Worker } else {
681*d57664e9SAndroid Build Coastguard Worker return strictly_order_type(ident, o.ident);
682*d57664e9SAndroid Build Coastguard Worker }
683*d57664e9SAndroid Build Coastguard Worker }
684*d57664e9SAndroid Build Coastguard Worker };
685*d57664e9SAndroid Build Coastguard Worker
686*d57664e9SAndroid Build Coastguard Worker
parseAndAddEntry(Bundle * bundle,const sp<AaptFile> & in,ResXMLTree * block,const ResTable_config & config,const String16 & myPackage,const String16 & curType,const String16 & ident,const String16 & curTag,bool curIsStyled,int32_t curFormat,bool isFormatted,const String16 & product,PseudolocalizationMethod pseudolocalize,const bool overwrite,KeyedVector<type_ident_pair_t,bool> * skippedResourceNames,ResourceTable * outTable)687*d57664e9SAndroid Build Coastguard Worker status_t parseAndAddEntry(Bundle* bundle,
688*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& in,
689*d57664e9SAndroid Build Coastguard Worker ResXMLTree* block,
690*d57664e9SAndroid Build Coastguard Worker const ResTable_config& config,
691*d57664e9SAndroid Build Coastguard Worker const String16& myPackage,
692*d57664e9SAndroid Build Coastguard Worker const String16& curType,
693*d57664e9SAndroid Build Coastguard Worker const String16& ident,
694*d57664e9SAndroid Build Coastguard Worker const String16& curTag,
695*d57664e9SAndroid Build Coastguard Worker bool curIsStyled,
696*d57664e9SAndroid Build Coastguard Worker int32_t curFormat,
697*d57664e9SAndroid Build Coastguard Worker bool isFormatted,
698*d57664e9SAndroid Build Coastguard Worker const String16& product,
699*d57664e9SAndroid Build Coastguard Worker PseudolocalizationMethod pseudolocalize,
700*d57664e9SAndroid Build Coastguard Worker const bool overwrite,
701*d57664e9SAndroid Build Coastguard Worker KeyedVector<type_ident_pair_t, bool>* skippedResourceNames,
702*d57664e9SAndroid Build Coastguard Worker ResourceTable* outTable)
703*d57664e9SAndroid Build Coastguard Worker {
704*d57664e9SAndroid Build Coastguard Worker status_t err;
705*d57664e9SAndroid Build Coastguard Worker
706*d57664e9SAndroid Build Coastguard Worker String16 str;
707*d57664e9SAndroid Build Coastguard Worker Vector<StringPool::entry_style_span> spans;
708*d57664e9SAndroid Build Coastguard Worker err = parseStyledString(bundle, in->getPrintableSource().c_str(), block,
709*d57664e9SAndroid Build Coastguard Worker curTag, &str, curIsStyled ? &spans : NULL,
710*d57664e9SAndroid Build Coastguard Worker isFormatted, pseudolocalize);
711*d57664e9SAndroid Build Coastguard Worker
712*d57664e9SAndroid Build Coastguard Worker if (err < NO_ERROR) {
713*d57664e9SAndroid Build Coastguard Worker return err;
714*d57664e9SAndroid Build Coastguard Worker }
715*d57664e9SAndroid Build Coastguard Worker
716*d57664e9SAndroid Build Coastguard Worker /*
717*d57664e9SAndroid Build Coastguard Worker * If a product type was specified on the command line
718*d57664e9SAndroid Build Coastguard Worker * and also in the string, and the two are not the same,
719*d57664e9SAndroid Build Coastguard Worker * return without adding the string.
720*d57664e9SAndroid Build Coastguard Worker */
721*d57664e9SAndroid Build Coastguard Worker
722*d57664e9SAndroid Build Coastguard Worker const char *bundleProduct = bundle->getProduct();
723*d57664e9SAndroid Build Coastguard Worker if (bundleProduct == NULL) {
724*d57664e9SAndroid Build Coastguard Worker bundleProduct = "";
725*d57664e9SAndroid Build Coastguard Worker }
726*d57664e9SAndroid Build Coastguard Worker
727*d57664e9SAndroid Build Coastguard Worker if (product.size() != 0) {
728*d57664e9SAndroid Build Coastguard Worker /*
729*d57664e9SAndroid Build Coastguard Worker * If the command-line-specified product is empty, only "default"
730*d57664e9SAndroid Build Coastguard Worker * matches. Other variants are skipped. This is so generation
731*d57664e9SAndroid Build Coastguard Worker * of the R.java file when the product is not known is predictable.
732*d57664e9SAndroid Build Coastguard Worker */
733*d57664e9SAndroid Build Coastguard Worker
734*d57664e9SAndroid Build Coastguard Worker if (bundleProduct[0] == '\0') {
735*d57664e9SAndroid Build Coastguard Worker if (strcmp16(String16("default").c_str(), product.c_str()) != 0) {
736*d57664e9SAndroid Build Coastguard Worker /*
737*d57664e9SAndroid Build Coastguard Worker * This string has a product other than 'default'. Do not add it,
738*d57664e9SAndroid Build Coastguard Worker * but record it so that if we do not see the same string with
739*d57664e9SAndroid Build Coastguard Worker * product 'default' or no product, then report an error.
740*d57664e9SAndroid Build Coastguard Worker */
741*d57664e9SAndroid Build Coastguard Worker skippedResourceNames->replaceValueFor(
742*d57664e9SAndroid Build Coastguard Worker type_ident_pair_t(curType, ident), true);
743*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
744*d57664e9SAndroid Build Coastguard Worker }
745*d57664e9SAndroid Build Coastguard Worker } else {
746*d57664e9SAndroid Build Coastguard Worker /*
747*d57664e9SAndroid Build Coastguard Worker * The command-line product is not empty.
748*d57664e9SAndroid Build Coastguard Worker * If the product for this string is on the command-line list,
749*d57664e9SAndroid Build Coastguard Worker * it matches. "default" also matches, but only if nothing
750*d57664e9SAndroid Build Coastguard Worker * else has matched already.
751*d57664e9SAndroid Build Coastguard Worker */
752*d57664e9SAndroid Build Coastguard Worker
753*d57664e9SAndroid Build Coastguard Worker if (isInProductList(product, String16(bundleProduct))) {
754*d57664e9SAndroid Build Coastguard Worker ;
755*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(String16("default").c_str(), product.c_str()) == 0 &&
756*d57664e9SAndroid Build Coastguard Worker !outTable->hasBagOrEntry(myPackage, curType, ident, config)) {
757*d57664e9SAndroid Build Coastguard Worker ;
758*d57664e9SAndroid Build Coastguard Worker } else {
759*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
760*d57664e9SAndroid Build Coastguard Worker }
761*d57664e9SAndroid Build Coastguard Worker }
762*d57664e9SAndroid Build Coastguard Worker }
763*d57664e9SAndroid Build Coastguard Worker
764*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
765*d57664e9SAndroid Build Coastguard Worker printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
766*d57664e9SAndroid Build Coastguard Worker config.language[0], config.language[1],
767*d57664e9SAndroid Build Coastguard Worker config.country[0], config.country[1],
768*d57664e9SAndroid Build Coastguard Worker config.orientation, config.density,
769*d57664e9SAndroid Build Coastguard Worker String8(ident).c_str(), String8(str).c_str());
770*d57664e9SAndroid Build Coastguard Worker }
771*d57664e9SAndroid Build Coastguard Worker
772*d57664e9SAndroid Build Coastguard Worker err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
773*d57664e9SAndroid Build Coastguard Worker myPackage, curType, ident, str, &spans, &config,
774*d57664e9SAndroid Build Coastguard Worker false, curFormat, overwrite);
775*d57664e9SAndroid Build Coastguard Worker
776*d57664e9SAndroid Build Coastguard Worker return err;
777*d57664e9SAndroid Build Coastguard Worker }
778*d57664e9SAndroid Build Coastguard Worker
compileResourceFile(Bundle * bundle,const sp<AaptAssets> & assets,const sp<AaptFile> & in,const ResTable_config & defParams,const bool overwrite,ResourceTable * outTable)779*d57664e9SAndroid Build Coastguard Worker status_t compileResourceFile(Bundle* bundle,
780*d57664e9SAndroid Build Coastguard Worker const sp<AaptAssets>& assets,
781*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& in,
782*d57664e9SAndroid Build Coastguard Worker const ResTable_config& defParams,
783*d57664e9SAndroid Build Coastguard Worker const bool overwrite,
784*d57664e9SAndroid Build Coastguard Worker ResourceTable* outTable)
785*d57664e9SAndroid Build Coastguard Worker {
786*d57664e9SAndroid Build Coastguard Worker ResXMLTree block;
787*d57664e9SAndroid Build Coastguard Worker status_t err = parseXMLResource(in, &block, false, true);
788*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
789*d57664e9SAndroid Build Coastguard Worker return err;
790*d57664e9SAndroid Build Coastguard Worker }
791*d57664e9SAndroid Build Coastguard Worker
792*d57664e9SAndroid Build Coastguard Worker // Top-level tag.
793*d57664e9SAndroid Build Coastguard Worker const String16 resources16("resources");
794*d57664e9SAndroid Build Coastguard Worker
795*d57664e9SAndroid Build Coastguard Worker // Identifier declaration tags.
796*d57664e9SAndroid Build Coastguard Worker const String16 declare_styleable16("declare-styleable");
797*d57664e9SAndroid Build Coastguard Worker const String16 attr16("attr");
798*d57664e9SAndroid Build Coastguard Worker
799*d57664e9SAndroid Build Coastguard Worker // Data creation organizational tags.
800*d57664e9SAndroid Build Coastguard Worker const String16 string16("string");
801*d57664e9SAndroid Build Coastguard Worker const String16 drawable16("drawable");
802*d57664e9SAndroid Build Coastguard Worker const String16 color16("color");
803*d57664e9SAndroid Build Coastguard Worker const String16 bool16("bool");
804*d57664e9SAndroid Build Coastguard Worker const String16 integer16("integer");
805*d57664e9SAndroid Build Coastguard Worker const String16 dimen16("dimen");
806*d57664e9SAndroid Build Coastguard Worker const String16 fraction16("fraction");
807*d57664e9SAndroid Build Coastguard Worker const String16 style16("style");
808*d57664e9SAndroid Build Coastguard Worker const String16 plurals16("plurals");
809*d57664e9SAndroid Build Coastguard Worker const String16 array16("array");
810*d57664e9SAndroid Build Coastguard Worker const String16 string_array16("string-array");
811*d57664e9SAndroid Build Coastguard Worker const String16 integer_array16("integer-array");
812*d57664e9SAndroid Build Coastguard Worker const String16 public16("public");
813*d57664e9SAndroid Build Coastguard Worker const String16 public_padding16("public-padding");
814*d57664e9SAndroid Build Coastguard Worker const String16 private_symbols16("private-symbols");
815*d57664e9SAndroid Build Coastguard Worker const String16 java_symbol16("java-symbol");
816*d57664e9SAndroid Build Coastguard Worker const String16 add_resource16("add-resource");
817*d57664e9SAndroid Build Coastguard Worker const String16 skip16("skip");
818*d57664e9SAndroid Build Coastguard Worker const String16 eat_comment16("eat-comment");
819*d57664e9SAndroid Build Coastguard Worker
820*d57664e9SAndroid Build Coastguard Worker // Data creation tags.
821*d57664e9SAndroid Build Coastguard Worker const String16 bag16("bag");
822*d57664e9SAndroid Build Coastguard Worker const String16 item16("item");
823*d57664e9SAndroid Build Coastguard Worker
824*d57664e9SAndroid Build Coastguard Worker // Attribute type constants.
825*d57664e9SAndroid Build Coastguard Worker const String16 enum16("enum");
826*d57664e9SAndroid Build Coastguard Worker
827*d57664e9SAndroid Build Coastguard Worker // plural values
828*d57664e9SAndroid Build Coastguard Worker const String16 other16("other");
829*d57664e9SAndroid Build Coastguard Worker const String16 quantityOther16("^other");
830*d57664e9SAndroid Build Coastguard Worker const String16 zero16("zero");
831*d57664e9SAndroid Build Coastguard Worker const String16 quantityZero16("^zero");
832*d57664e9SAndroid Build Coastguard Worker const String16 one16("one");
833*d57664e9SAndroid Build Coastguard Worker const String16 quantityOne16("^one");
834*d57664e9SAndroid Build Coastguard Worker const String16 two16("two");
835*d57664e9SAndroid Build Coastguard Worker const String16 quantityTwo16("^two");
836*d57664e9SAndroid Build Coastguard Worker const String16 few16("few");
837*d57664e9SAndroid Build Coastguard Worker const String16 quantityFew16("^few");
838*d57664e9SAndroid Build Coastguard Worker const String16 many16("many");
839*d57664e9SAndroid Build Coastguard Worker const String16 quantityMany16("^many");
840*d57664e9SAndroid Build Coastguard Worker
841*d57664e9SAndroid Build Coastguard Worker // useful attribute names and special values
842*d57664e9SAndroid Build Coastguard Worker const String16 name16("name");
843*d57664e9SAndroid Build Coastguard Worker const String16 translatable16("translatable");
844*d57664e9SAndroid Build Coastguard Worker const String16 formatted16("formatted");
845*d57664e9SAndroid Build Coastguard Worker const String16 false16("false");
846*d57664e9SAndroid Build Coastguard Worker
847*d57664e9SAndroid Build Coastguard Worker const String16 myPackage(assets->getPackage());
848*d57664e9SAndroid Build Coastguard Worker
849*d57664e9SAndroid Build Coastguard Worker bool hasErrors = false;
850*d57664e9SAndroid Build Coastguard Worker
851*d57664e9SAndroid Build Coastguard Worker bool fileIsTranslatable = true;
852*d57664e9SAndroid Build Coastguard Worker if (strstr(in->getPrintableSource().c_str(), "donottranslate") != NULL) {
853*d57664e9SAndroid Build Coastguard Worker fileIsTranslatable = false;
854*d57664e9SAndroid Build Coastguard Worker }
855*d57664e9SAndroid Build Coastguard Worker
856*d57664e9SAndroid Build Coastguard Worker DefaultKeyedVector<String16, uint32_t> nextPublicId(0);
857*d57664e9SAndroid Build Coastguard Worker
858*d57664e9SAndroid Build Coastguard Worker // Stores the resource names that were skipped. Typically this happens when
859*d57664e9SAndroid Build Coastguard Worker // AAPT is invoked without a product specified and a resource has no
860*d57664e9SAndroid Build Coastguard Worker // 'default' product attribute.
861*d57664e9SAndroid Build Coastguard Worker KeyedVector<type_ident_pair_t, bool> skippedResourceNames;
862*d57664e9SAndroid Build Coastguard Worker
863*d57664e9SAndroid Build Coastguard Worker ResXMLTree::event_code_t code;
864*d57664e9SAndroid Build Coastguard Worker do {
865*d57664e9SAndroid Build Coastguard Worker code = block.next();
866*d57664e9SAndroid Build Coastguard Worker } while (code == ResXMLTree::START_NAMESPACE);
867*d57664e9SAndroid Build Coastguard Worker
868*d57664e9SAndroid Build Coastguard Worker size_t len;
869*d57664e9SAndroid Build Coastguard Worker if (code != ResXMLTree::START_TAG) {
870*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
871*d57664e9SAndroid Build Coastguard Worker "No start tag found\n");
872*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
873*d57664e9SAndroid Build Coastguard Worker }
874*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), resources16.c_str()) != 0) {
875*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
876*d57664e9SAndroid Build Coastguard Worker "Invalid start tag %s\n", String8(block.getElementName(&len)).c_str());
877*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
878*d57664e9SAndroid Build Coastguard Worker }
879*d57664e9SAndroid Build Coastguard Worker
880*d57664e9SAndroid Build Coastguard Worker ResTable_config curParams(defParams);
881*d57664e9SAndroid Build Coastguard Worker
882*d57664e9SAndroid Build Coastguard Worker ResTable_config pseudoParams(curParams);
883*d57664e9SAndroid Build Coastguard Worker pseudoParams.language[0] = 'e';
884*d57664e9SAndroid Build Coastguard Worker pseudoParams.language[1] = 'n';
885*d57664e9SAndroid Build Coastguard Worker pseudoParams.country[0] = 'X';
886*d57664e9SAndroid Build Coastguard Worker pseudoParams.country[1] = 'A';
887*d57664e9SAndroid Build Coastguard Worker
888*d57664e9SAndroid Build Coastguard Worker ResTable_config pseudoBidiParams(curParams);
889*d57664e9SAndroid Build Coastguard Worker pseudoBidiParams.language[0] = 'a';
890*d57664e9SAndroid Build Coastguard Worker pseudoBidiParams.language[1] = 'r';
891*d57664e9SAndroid Build Coastguard Worker pseudoBidiParams.country[0] = 'X';
892*d57664e9SAndroid Build Coastguard Worker pseudoBidiParams.country[1] = 'B';
893*d57664e9SAndroid Build Coastguard Worker
894*d57664e9SAndroid Build Coastguard Worker // We should skip resources for pseudolocales if they were
895*d57664e9SAndroid Build Coastguard Worker // already added automatically. This is a fix for a transition period when
896*d57664e9SAndroid Build Coastguard Worker // manually pseudolocalized resources may be expected.
897*d57664e9SAndroid Build Coastguard Worker // TODO: remove this check after next SDK version release.
898*d57664e9SAndroid Build Coastguard Worker if ((bundle->getPseudolocalize() & PSEUDO_ACCENTED &&
899*d57664e9SAndroid Build Coastguard Worker curParams.locale == pseudoParams.locale) ||
900*d57664e9SAndroid Build Coastguard Worker (bundle->getPseudolocalize() & PSEUDO_BIDI &&
901*d57664e9SAndroid Build Coastguard Worker curParams.locale == pseudoBidiParams.locale)) {
902*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), 0).warning(
903*d57664e9SAndroid Build Coastguard Worker "Resource file %s is skipped as pseudolocalization"
904*d57664e9SAndroid Build Coastguard Worker " was done automatically.",
905*d57664e9SAndroid Build Coastguard Worker in->getPrintableSource().c_str());
906*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
907*d57664e9SAndroid Build Coastguard Worker }
908*d57664e9SAndroid Build Coastguard Worker
909*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
910*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::START_TAG) {
911*d57664e9SAndroid Build Coastguard Worker const String16* curTag = NULL;
912*d57664e9SAndroid Build Coastguard Worker String16 curType;
913*d57664e9SAndroid Build Coastguard Worker String16 curName;
914*d57664e9SAndroid Build Coastguard Worker int32_t curFormat = ResTable_map::TYPE_ANY;
915*d57664e9SAndroid Build Coastguard Worker bool curIsBag = false;
916*d57664e9SAndroid Build Coastguard Worker bool curIsBagReplaceOnOverwrite = false;
917*d57664e9SAndroid Build Coastguard Worker bool curIsStyled = false;
918*d57664e9SAndroid Build Coastguard Worker bool curIsPseudolocalizable = false;
919*d57664e9SAndroid Build Coastguard Worker bool curIsFormatted = fileIsTranslatable;
920*d57664e9SAndroid Build Coastguard Worker bool localHasErrors = false;
921*d57664e9SAndroid Build Coastguard Worker
922*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
923*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT
924*d57664e9SAndroid Build Coastguard Worker && code != ResXMLTree::BAD_DOCUMENT) {
925*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
926*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
927*d57664e9SAndroid Build Coastguard Worker break;
928*d57664e9SAndroid Build Coastguard Worker }
929*d57664e9SAndroid Build Coastguard Worker }
930*d57664e9SAndroid Build Coastguard Worker }
931*d57664e9SAndroid Build Coastguard Worker continue;
932*d57664e9SAndroid Build Coastguard Worker
933*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
934*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT
935*d57664e9SAndroid Build Coastguard Worker && code != ResXMLTree::BAD_DOCUMENT) {
936*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
937*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
938*d57664e9SAndroid Build Coastguard Worker break;
939*d57664e9SAndroid Build Coastguard Worker }
940*d57664e9SAndroid Build Coastguard Worker }
941*d57664e9SAndroid Build Coastguard Worker }
942*d57664e9SAndroid Build Coastguard Worker continue;
943*d57664e9SAndroid Build Coastguard Worker
944*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), public16.c_str()) == 0) {
945*d57664e9SAndroid Build Coastguard Worker SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
946*d57664e9SAndroid Build Coastguard Worker
947*d57664e9SAndroid Build Coastguard Worker String16 type;
948*d57664e9SAndroid Build Coastguard Worker ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
949*d57664e9SAndroid Build Coastguard Worker if (typeIdx < 0) {
950*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'type' attribute is required for <public>\n");
951*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
952*d57664e9SAndroid Build Coastguard Worker }
953*d57664e9SAndroid Build Coastguard Worker type = String16(block.getAttributeStringValue(typeIdx, &len));
954*d57664e9SAndroid Build Coastguard Worker
955*d57664e9SAndroid Build Coastguard Worker String16 name;
956*d57664e9SAndroid Build Coastguard Worker ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
957*d57664e9SAndroid Build Coastguard Worker if (nameIdx < 0) {
958*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'name' attribute is required for <public>\n");
959*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
960*d57664e9SAndroid Build Coastguard Worker }
961*d57664e9SAndroid Build Coastguard Worker name = String16(block.getAttributeStringValue(nameIdx, &len));
962*d57664e9SAndroid Build Coastguard Worker
963*d57664e9SAndroid Build Coastguard Worker uint32_t ident = 0;
964*d57664e9SAndroid Build Coastguard Worker ssize_t identIdx = block.indexOfAttribute(NULL, "id");
965*d57664e9SAndroid Build Coastguard Worker if (identIdx >= 0) {
966*d57664e9SAndroid Build Coastguard Worker const char16_t* identStr = block.getAttributeStringValue(identIdx, &len);
967*d57664e9SAndroid Build Coastguard Worker Res_value identValue;
968*d57664e9SAndroid Build Coastguard Worker if (!ResTable::stringToInt(identStr, len, &identValue)) {
969*d57664e9SAndroid Build Coastguard Worker srcPos.error("Given 'id' attribute is not an integer: %s\n",
970*d57664e9SAndroid Build Coastguard Worker String8(block.getAttributeStringValue(identIdx, &len)).c_str());
971*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
972*d57664e9SAndroid Build Coastguard Worker } else {
973*d57664e9SAndroid Build Coastguard Worker ident = identValue.data;
974*d57664e9SAndroid Build Coastguard Worker nextPublicId.replaceValueFor(type, ident+1);
975*d57664e9SAndroid Build Coastguard Worker }
976*d57664e9SAndroid Build Coastguard Worker } else if (nextPublicId.indexOfKey(type) < 0) {
977*d57664e9SAndroid Build Coastguard Worker srcPos.error("No 'id' attribute supplied <public>,"
978*d57664e9SAndroid Build Coastguard Worker " and no previous id defined in this file.\n");
979*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
980*d57664e9SAndroid Build Coastguard Worker } else if (!localHasErrors) {
981*d57664e9SAndroid Build Coastguard Worker ident = nextPublicId.valueFor(type);
982*d57664e9SAndroid Build Coastguard Worker nextPublicId.replaceValueFor(type, ident+1);
983*d57664e9SAndroid Build Coastguard Worker }
984*d57664e9SAndroid Build Coastguard Worker
985*d57664e9SAndroid Build Coastguard Worker if (!localHasErrors) {
986*d57664e9SAndroid Build Coastguard Worker err = outTable->addPublic(srcPos, myPackage, type, name, ident);
987*d57664e9SAndroid Build Coastguard Worker if (err < NO_ERROR) {
988*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
989*d57664e9SAndroid Build Coastguard Worker }
990*d57664e9SAndroid Build Coastguard Worker }
991*d57664e9SAndroid Build Coastguard Worker if (!localHasErrors) {
992*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
993*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
994*d57664e9SAndroid Build Coastguard Worker symbols = symbols->addNestedSymbol(String8(type), srcPos);
995*d57664e9SAndroid Build Coastguard Worker }
996*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
997*d57664e9SAndroid Build Coastguard Worker symbols->makeSymbolPublic(String8(name), srcPos);
998*d57664e9SAndroid Build Coastguard Worker String16 comment(
999*d57664e9SAndroid Build Coastguard Worker block.getComment(&len) ? block.getComment(&len) : nulStr);
1000*d57664e9SAndroid Build Coastguard Worker symbols->appendComment(String8(name), comment, srcPos);
1001*d57664e9SAndroid Build Coastguard Worker } else {
1002*d57664e9SAndroid Build Coastguard Worker srcPos.error("Unable to create symbols!\n");
1003*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1004*d57664e9SAndroid Build Coastguard Worker }
1005*d57664e9SAndroid Build Coastguard Worker }
1006*d57664e9SAndroid Build Coastguard Worker
1007*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1008*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1009*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), public16.c_str()) == 0) {
1010*d57664e9SAndroid Build Coastguard Worker break;
1011*d57664e9SAndroid Build Coastguard Worker }
1012*d57664e9SAndroid Build Coastguard Worker }
1013*d57664e9SAndroid Build Coastguard Worker }
1014*d57664e9SAndroid Build Coastguard Worker continue;
1015*d57664e9SAndroid Build Coastguard Worker
1016*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), public_padding16.c_str()) == 0) {
1017*d57664e9SAndroid Build Coastguard Worker SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1018*d57664e9SAndroid Build Coastguard Worker
1019*d57664e9SAndroid Build Coastguard Worker String16 type;
1020*d57664e9SAndroid Build Coastguard Worker ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
1021*d57664e9SAndroid Build Coastguard Worker if (typeIdx < 0) {
1022*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'type' attribute is required for <public-padding>\n");
1023*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1024*d57664e9SAndroid Build Coastguard Worker }
1025*d57664e9SAndroid Build Coastguard Worker type = String16(block.getAttributeStringValue(typeIdx, &len));
1026*d57664e9SAndroid Build Coastguard Worker
1027*d57664e9SAndroid Build Coastguard Worker String16 name;
1028*d57664e9SAndroid Build Coastguard Worker ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1029*d57664e9SAndroid Build Coastguard Worker if (nameIdx < 0) {
1030*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'name' attribute is required for <public-padding>\n");
1031*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1032*d57664e9SAndroid Build Coastguard Worker }
1033*d57664e9SAndroid Build Coastguard Worker name = String16(block.getAttributeStringValue(nameIdx, &len));
1034*d57664e9SAndroid Build Coastguard Worker
1035*d57664e9SAndroid Build Coastguard Worker uint32_t start = 0;
1036*d57664e9SAndroid Build Coastguard Worker ssize_t startIdx = block.indexOfAttribute(NULL, "start");
1037*d57664e9SAndroid Build Coastguard Worker if (startIdx >= 0) {
1038*d57664e9SAndroid Build Coastguard Worker const char16_t* startStr = block.getAttributeStringValue(startIdx, &len);
1039*d57664e9SAndroid Build Coastguard Worker Res_value startValue;
1040*d57664e9SAndroid Build Coastguard Worker if (!ResTable::stringToInt(startStr, len, &startValue)) {
1041*d57664e9SAndroid Build Coastguard Worker srcPos.error("Given 'start' attribute is not an integer: %s\n",
1042*d57664e9SAndroid Build Coastguard Worker String8(block.getAttributeStringValue(startIdx, &len)).c_str());
1043*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1044*d57664e9SAndroid Build Coastguard Worker } else {
1045*d57664e9SAndroid Build Coastguard Worker start = startValue.data;
1046*d57664e9SAndroid Build Coastguard Worker }
1047*d57664e9SAndroid Build Coastguard Worker } else if (nextPublicId.indexOfKey(type) < 0) {
1048*d57664e9SAndroid Build Coastguard Worker srcPos.error("No 'start' attribute supplied <public-padding>,"
1049*d57664e9SAndroid Build Coastguard Worker " and no previous id defined in this file.\n");
1050*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1051*d57664e9SAndroid Build Coastguard Worker } else if (!localHasErrors) {
1052*d57664e9SAndroid Build Coastguard Worker start = nextPublicId.valueFor(type);
1053*d57664e9SAndroid Build Coastguard Worker }
1054*d57664e9SAndroid Build Coastguard Worker
1055*d57664e9SAndroid Build Coastguard Worker uint32_t end = 0;
1056*d57664e9SAndroid Build Coastguard Worker ssize_t endIdx = block.indexOfAttribute(NULL, "end");
1057*d57664e9SAndroid Build Coastguard Worker if (endIdx >= 0) {
1058*d57664e9SAndroid Build Coastguard Worker const char16_t* endStr = block.getAttributeStringValue(endIdx, &len);
1059*d57664e9SAndroid Build Coastguard Worker Res_value endValue;
1060*d57664e9SAndroid Build Coastguard Worker if (!ResTable::stringToInt(endStr, len, &endValue)) {
1061*d57664e9SAndroid Build Coastguard Worker srcPos.error("Given 'end' attribute is not an integer: %s\n",
1062*d57664e9SAndroid Build Coastguard Worker String8(block.getAttributeStringValue(endIdx, &len)).c_str());
1063*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1064*d57664e9SAndroid Build Coastguard Worker } else {
1065*d57664e9SAndroid Build Coastguard Worker end = endValue.data;
1066*d57664e9SAndroid Build Coastguard Worker }
1067*d57664e9SAndroid Build Coastguard Worker } else {
1068*d57664e9SAndroid Build Coastguard Worker srcPos.error("No 'end' attribute supplied <public-padding>\n");
1069*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1070*d57664e9SAndroid Build Coastguard Worker }
1071*d57664e9SAndroid Build Coastguard Worker
1072*d57664e9SAndroid Build Coastguard Worker if (end >= start) {
1073*d57664e9SAndroid Build Coastguard Worker nextPublicId.replaceValueFor(type, end+1);
1074*d57664e9SAndroid Build Coastguard Worker } else {
1075*d57664e9SAndroid Build Coastguard Worker srcPos.error("Padding start '%ul' is after end '%ul'\n",
1076*d57664e9SAndroid Build Coastguard Worker start, end);
1077*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1078*d57664e9SAndroid Build Coastguard Worker }
1079*d57664e9SAndroid Build Coastguard Worker
1080*d57664e9SAndroid Build Coastguard Worker String16 comment(
1081*d57664e9SAndroid Build Coastguard Worker block.getComment(&len) ? block.getComment(&len) : nulStr);
1082*d57664e9SAndroid Build Coastguard Worker for (uint32_t curIdent=start; curIdent<=end; curIdent++) {
1083*d57664e9SAndroid Build Coastguard Worker if (localHasErrors) {
1084*d57664e9SAndroid Build Coastguard Worker break;
1085*d57664e9SAndroid Build Coastguard Worker }
1086*d57664e9SAndroid Build Coastguard Worker String16 curName(name);
1087*d57664e9SAndroid Build Coastguard Worker char buf[64];
1088*d57664e9SAndroid Build Coastguard Worker sprintf(buf, "%d", (int)(end-curIdent+1));
1089*d57664e9SAndroid Build Coastguard Worker curName.append(String16(buf));
1090*d57664e9SAndroid Build Coastguard Worker
1091*d57664e9SAndroid Build Coastguard Worker err = outTable->addEntry(srcPos, myPackage, type, curName,
1092*d57664e9SAndroid Build Coastguard Worker String16("padding"), NULL, &curParams, false,
1093*d57664e9SAndroid Build Coastguard Worker ResTable_map::TYPE_STRING, overwrite);
1094*d57664e9SAndroid Build Coastguard Worker if (err < NO_ERROR) {
1095*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1096*d57664e9SAndroid Build Coastguard Worker break;
1097*d57664e9SAndroid Build Coastguard Worker }
1098*d57664e9SAndroid Build Coastguard Worker err = outTable->addPublic(srcPos, myPackage, type,
1099*d57664e9SAndroid Build Coastguard Worker curName, curIdent);
1100*d57664e9SAndroid Build Coastguard Worker if (err < NO_ERROR) {
1101*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1102*d57664e9SAndroid Build Coastguard Worker break;
1103*d57664e9SAndroid Build Coastguard Worker }
1104*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
1105*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1106*d57664e9SAndroid Build Coastguard Worker symbols = symbols->addNestedSymbol(String8(type), srcPos);
1107*d57664e9SAndroid Build Coastguard Worker }
1108*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1109*d57664e9SAndroid Build Coastguard Worker symbols->makeSymbolPublic(String8(curName), srcPos);
1110*d57664e9SAndroid Build Coastguard Worker symbols->appendComment(String8(curName), comment, srcPos);
1111*d57664e9SAndroid Build Coastguard Worker } else {
1112*d57664e9SAndroid Build Coastguard Worker srcPos.error("Unable to create symbols!\n");
1113*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1114*d57664e9SAndroid Build Coastguard Worker }
1115*d57664e9SAndroid Build Coastguard Worker }
1116*d57664e9SAndroid Build Coastguard Worker
1117*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1118*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1119*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), public_padding16.c_str()) == 0) {
1120*d57664e9SAndroid Build Coastguard Worker break;
1121*d57664e9SAndroid Build Coastguard Worker }
1122*d57664e9SAndroid Build Coastguard Worker }
1123*d57664e9SAndroid Build Coastguard Worker }
1124*d57664e9SAndroid Build Coastguard Worker continue;
1125*d57664e9SAndroid Build Coastguard Worker
1126*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), private_symbols16.c_str()) == 0) {
1127*d57664e9SAndroid Build Coastguard Worker String16 pkg;
1128*d57664e9SAndroid Build Coastguard Worker ssize_t pkgIdx = block.indexOfAttribute(NULL, "package");
1129*d57664e9SAndroid Build Coastguard Worker if (pkgIdx < 0) {
1130*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1131*d57664e9SAndroid Build Coastguard Worker "A 'package' attribute is required for <private-symbols>\n");
1132*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1133*d57664e9SAndroid Build Coastguard Worker }
1134*d57664e9SAndroid Build Coastguard Worker pkg = String16(block.getAttributeStringValue(pkgIdx, &len));
1135*d57664e9SAndroid Build Coastguard Worker if (!localHasErrors) {
1136*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
1137*d57664e9SAndroid Build Coastguard Worker "<private-symbols> is deprecated. Use the command line flag "
1138*d57664e9SAndroid Build Coastguard Worker "--private-symbols instead.\n");
1139*d57664e9SAndroid Build Coastguard Worker if (assets->havePrivateSymbols()) {
1140*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
1141*d57664e9SAndroid Build Coastguard Worker "private symbol package already specified. Ignoring...\n");
1142*d57664e9SAndroid Build Coastguard Worker } else {
1143*d57664e9SAndroid Build Coastguard Worker assets->setSymbolsPrivatePackage(String8(pkg));
1144*d57664e9SAndroid Build Coastguard Worker }
1145*d57664e9SAndroid Build Coastguard Worker }
1146*d57664e9SAndroid Build Coastguard Worker
1147*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1148*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1149*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), private_symbols16.c_str()) == 0) {
1150*d57664e9SAndroid Build Coastguard Worker break;
1151*d57664e9SAndroid Build Coastguard Worker }
1152*d57664e9SAndroid Build Coastguard Worker }
1153*d57664e9SAndroid Build Coastguard Worker }
1154*d57664e9SAndroid Build Coastguard Worker continue;
1155*d57664e9SAndroid Build Coastguard Worker
1156*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), java_symbol16.c_str()) == 0) {
1157*d57664e9SAndroid Build Coastguard Worker SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1158*d57664e9SAndroid Build Coastguard Worker
1159*d57664e9SAndroid Build Coastguard Worker String16 type;
1160*d57664e9SAndroid Build Coastguard Worker ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
1161*d57664e9SAndroid Build Coastguard Worker if (typeIdx < 0) {
1162*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'type' attribute is required for <public>\n");
1163*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1164*d57664e9SAndroid Build Coastguard Worker }
1165*d57664e9SAndroid Build Coastguard Worker type = String16(block.getAttributeStringValue(typeIdx, &len));
1166*d57664e9SAndroid Build Coastguard Worker
1167*d57664e9SAndroid Build Coastguard Worker String16 name;
1168*d57664e9SAndroid Build Coastguard Worker ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1169*d57664e9SAndroid Build Coastguard Worker if (nameIdx < 0) {
1170*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'name' attribute is required for <public>\n");
1171*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1172*d57664e9SAndroid Build Coastguard Worker }
1173*d57664e9SAndroid Build Coastguard Worker name = String16(block.getAttributeStringValue(nameIdx, &len));
1174*d57664e9SAndroid Build Coastguard Worker
1175*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> symbols = assets->getJavaSymbolsFor(String8("R"));
1176*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1177*d57664e9SAndroid Build Coastguard Worker symbols = symbols->addNestedSymbol(String8(type), srcPos);
1178*d57664e9SAndroid Build Coastguard Worker }
1179*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1180*d57664e9SAndroid Build Coastguard Worker symbols->makeSymbolJavaSymbol(String8(name), srcPos);
1181*d57664e9SAndroid Build Coastguard Worker String16 comment(
1182*d57664e9SAndroid Build Coastguard Worker block.getComment(&len) ? block.getComment(&len) : nulStr);
1183*d57664e9SAndroid Build Coastguard Worker symbols->appendComment(String8(name), comment, srcPos);
1184*d57664e9SAndroid Build Coastguard Worker } else {
1185*d57664e9SAndroid Build Coastguard Worker srcPos.error("Unable to create symbols!\n");
1186*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1187*d57664e9SAndroid Build Coastguard Worker }
1188*d57664e9SAndroid Build Coastguard Worker
1189*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1190*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1191*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), java_symbol16.c_str()) == 0) {
1192*d57664e9SAndroid Build Coastguard Worker break;
1193*d57664e9SAndroid Build Coastguard Worker }
1194*d57664e9SAndroid Build Coastguard Worker }
1195*d57664e9SAndroid Build Coastguard Worker }
1196*d57664e9SAndroid Build Coastguard Worker continue;
1197*d57664e9SAndroid Build Coastguard Worker
1198*d57664e9SAndroid Build Coastguard Worker
1199*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), add_resource16.c_str()) == 0) {
1200*d57664e9SAndroid Build Coastguard Worker SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1201*d57664e9SAndroid Build Coastguard Worker
1202*d57664e9SAndroid Build Coastguard Worker String16 typeName;
1203*d57664e9SAndroid Build Coastguard Worker ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
1204*d57664e9SAndroid Build Coastguard Worker if (typeIdx < 0) {
1205*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'type' attribute is required for <add-resource>\n");
1206*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1207*d57664e9SAndroid Build Coastguard Worker }
1208*d57664e9SAndroid Build Coastguard Worker typeName = String16(block.getAttributeStringValue(typeIdx, &len));
1209*d57664e9SAndroid Build Coastguard Worker
1210*d57664e9SAndroid Build Coastguard Worker String16 name;
1211*d57664e9SAndroid Build Coastguard Worker ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1212*d57664e9SAndroid Build Coastguard Worker if (nameIdx < 0) {
1213*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'name' attribute is required for <add-resource>\n");
1214*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1215*d57664e9SAndroid Build Coastguard Worker }
1216*d57664e9SAndroid Build Coastguard Worker name = String16(block.getAttributeStringValue(nameIdx, &len));
1217*d57664e9SAndroid Build Coastguard Worker
1218*d57664e9SAndroid Build Coastguard Worker outTable->canAddEntry(srcPos, myPackage, typeName, name);
1219*d57664e9SAndroid Build Coastguard Worker
1220*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1221*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1222*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), add_resource16.c_str()) == 0) {
1223*d57664e9SAndroid Build Coastguard Worker break;
1224*d57664e9SAndroid Build Coastguard Worker }
1225*d57664e9SAndroid Build Coastguard Worker }
1226*d57664e9SAndroid Build Coastguard Worker }
1227*d57664e9SAndroid Build Coastguard Worker continue;
1228*d57664e9SAndroid Build Coastguard Worker
1229*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), declare_styleable16.c_str()) == 0) {
1230*d57664e9SAndroid Build Coastguard Worker SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
1231*d57664e9SAndroid Build Coastguard Worker
1232*d57664e9SAndroid Build Coastguard Worker String16 ident;
1233*d57664e9SAndroid Build Coastguard Worker ssize_t identIdx = block.indexOfAttribute(NULL, "name");
1234*d57664e9SAndroid Build Coastguard Worker if (identIdx < 0) {
1235*d57664e9SAndroid Build Coastguard Worker srcPos.error("A 'name' attribute is required for <declare-styleable>\n");
1236*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1237*d57664e9SAndroid Build Coastguard Worker }
1238*d57664e9SAndroid Build Coastguard Worker ident = String16(block.getAttributeStringValue(identIdx, &len));
1239*d57664e9SAndroid Build Coastguard Worker
1240*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
1241*d57664e9SAndroid Build Coastguard Worker if (!localHasErrors) {
1242*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1243*d57664e9SAndroid Build Coastguard Worker symbols = symbols->addNestedSymbol(String8("styleable"), srcPos);
1244*d57664e9SAndroid Build Coastguard Worker }
1245*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> styleSymbols = symbols;
1246*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1247*d57664e9SAndroid Build Coastguard Worker symbols = symbols->addNestedSymbol(String8(ident), srcPos);
1248*d57664e9SAndroid Build Coastguard Worker }
1249*d57664e9SAndroid Build Coastguard Worker if (symbols == NULL) {
1250*d57664e9SAndroid Build Coastguard Worker srcPos.error("Unable to create symbols!\n");
1251*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1252*d57664e9SAndroid Build Coastguard Worker }
1253*d57664e9SAndroid Build Coastguard Worker
1254*d57664e9SAndroid Build Coastguard Worker String16 comment(
1255*d57664e9SAndroid Build Coastguard Worker block.getComment(&len) ? block.getComment(&len) : nulStr);
1256*d57664e9SAndroid Build Coastguard Worker styleSymbols->appendComment(String8(ident), comment, srcPos);
1257*d57664e9SAndroid Build Coastguard Worker } else {
1258*d57664e9SAndroid Build Coastguard Worker symbols = NULL;
1259*d57664e9SAndroid Build Coastguard Worker }
1260*d57664e9SAndroid Build Coastguard Worker
1261*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
1262*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::START_TAG) {
1263*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
1264*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT
1265*d57664e9SAndroid Build Coastguard Worker && code != ResXMLTree::BAD_DOCUMENT) {
1266*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1267*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
1268*d57664e9SAndroid Build Coastguard Worker break;
1269*d57664e9SAndroid Build Coastguard Worker }
1270*d57664e9SAndroid Build Coastguard Worker }
1271*d57664e9SAndroid Build Coastguard Worker }
1272*d57664e9SAndroid Build Coastguard Worker continue;
1273*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
1274*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT
1275*d57664e9SAndroid Build Coastguard Worker && code != ResXMLTree::BAD_DOCUMENT) {
1276*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::END_TAG) {
1277*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
1278*d57664e9SAndroid Build Coastguard Worker break;
1279*d57664e9SAndroid Build Coastguard Worker }
1280*d57664e9SAndroid Build Coastguard Worker }
1281*d57664e9SAndroid Build Coastguard Worker }
1282*d57664e9SAndroid Build Coastguard Worker continue;
1283*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), attr16.c_str()) != 0) {
1284*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1285*d57664e9SAndroid Build Coastguard Worker "Tag <%s> can not appear inside <declare-styleable>, only <attr>\n",
1286*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str());
1287*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1288*d57664e9SAndroid Build Coastguard Worker }
1289*d57664e9SAndroid Build Coastguard Worker
1290*d57664e9SAndroid Build Coastguard Worker String16 comment(
1291*d57664e9SAndroid Build Coastguard Worker block.getComment(&len) ? block.getComment(&len) : nulStr);
1292*d57664e9SAndroid Build Coastguard Worker String16 itemIdent;
1293*d57664e9SAndroid Build Coastguard Worker err = compileAttribute(in, block, myPackage, outTable, &itemIdent, true);
1294*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1295*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1296*d57664e9SAndroid Build Coastguard Worker }
1297*d57664e9SAndroid Build Coastguard Worker
1298*d57664e9SAndroid Build Coastguard Worker if (symbols != NULL) {
1299*d57664e9SAndroid Build Coastguard Worker SourcePos srcPos(String8(in->getPrintableSource()), block.getLineNumber());
1300*d57664e9SAndroid Build Coastguard Worker symbols->addSymbol(String8(itemIdent), 0, srcPos);
1301*d57664e9SAndroid Build Coastguard Worker symbols->appendComment(String8(itemIdent), comment, srcPos);
1302*d57664e9SAndroid Build Coastguard Worker //printf("Attribute %s comment: %s\n", String8(itemIdent).c_str(),
1303*d57664e9SAndroid Build Coastguard Worker // String8(comment).c_str());
1304*d57664e9SAndroid Build Coastguard Worker }
1305*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::END_TAG) {
1306*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), declare_styleable16.c_str()) == 0) {
1307*d57664e9SAndroid Build Coastguard Worker break;
1308*d57664e9SAndroid Build Coastguard Worker }
1309*d57664e9SAndroid Build Coastguard Worker
1310*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1311*d57664e9SAndroid Build Coastguard Worker "Found tag </%s> where </attr> is expected\n",
1312*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str());
1313*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1314*d57664e9SAndroid Build Coastguard Worker }
1315*d57664e9SAndroid Build Coastguard Worker }
1316*d57664e9SAndroid Build Coastguard Worker continue;
1317*d57664e9SAndroid Build Coastguard Worker
1318*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), attr16.c_str()) == 0) {
1319*d57664e9SAndroid Build Coastguard Worker err = compileAttribute(in, block, myPackage, outTable, NULL);
1320*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1321*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
1322*d57664e9SAndroid Build Coastguard Worker }
1323*d57664e9SAndroid Build Coastguard Worker continue;
1324*d57664e9SAndroid Build Coastguard Worker
1325*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), item16.c_str()) == 0) {
1326*d57664e9SAndroid Build Coastguard Worker curTag = &item16;
1327*d57664e9SAndroid Build Coastguard Worker ssize_t attri = block.indexOfAttribute(NULL, "type");
1328*d57664e9SAndroid Build Coastguard Worker if (attri >= 0) {
1329*d57664e9SAndroid Build Coastguard Worker curType = String16(block.getAttributeStringValue(attri, &len));
1330*d57664e9SAndroid Build Coastguard Worker ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
1331*d57664e9SAndroid Build Coastguard Worker if (nameIdx >= 0) {
1332*d57664e9SAndroid Build Coastguard Worker curName = String16(block.getAttributeStringValue(nameIdx, &len));
1333*d57664e9SAndroid Build Coastguard Worker }
1334*d57664e9SAndroid Build Coastguard Worker ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
1335*d57664e9SAndroid Build Coastguard Worker if (formatIdx >= 0) {
1336*d57664e9SAndroid Build Coastguard Worker String16 formatStr = String16(block.getAttributeStringValue(
1337*d57664e9SAndroid Build Coastguard Worker formatIdx, &len));
1338*d57664e9SAndroid Build Coastguard Worker curFormat = parse_flags(formatStr.c_str(), formatStr.size(),
1339*d57664e9SAndroid Build Coastguard Worker gFormatFlags);
1340*d57664e9SAndroid Build Coastguard Worker if (curFormat == 0) {
1341*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1342*d57664e9SAndroid Build Coastguard Worker "Tag <item> 'format' attribute value \"%s\" not valid\n",
1343*d57664e9SAndroid Build Coastguard Worker String8(formatStr).c_str());
1344*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1345*d57664e9SAndroid Build Coastguard Worker }
1346*d57664e9SAndroid Build Coastguard Worker }
1347*d57664e9SAndroid Build Coastguard Worker } else {
1348*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1349*d57664e9SAndroid Build Coastguard Worker "A 'type' attribute is required for <item>\n");
1350*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1351*d57664e9SAndroid Build Coastguard Worker }
1352*d57664e9SAndroid Build Coastguard Worker curIsStyled = true;
1353*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), string16.c_str()) == 0) {
1354*d57664e9SAndroid Build Coastguard Worker // Note the existence and locale of every string we process
1355*d57664e9SAndroid Build Coastguard Worker char rawLocale[RESTABLE_MAX_LOCALE_LEN];
1356*d57664e9SAndroid Build Coastguard Worker curParams.getBcp47Locale(rawLocale);
1357*d57664e9SAndroid Build Coastguard Worker String8 locale(rawLocale);
1358*d57664e9SAndroid Build Coastguard Worker String16 name;
1359*d57664e9SAndroid Build Coastguard Worker String16 translatable;
1360*d57664e9SAndroid Build Coastguard Worker String16 formatted;
1361*d57664e9SAndroid Build Coastguard Worker
1362*d57664e9SAndroid Build Coastguard Worker size_t n = block.getAttributeCount();
1363*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < n; i++) {
1364*d57664e9SAndroid Build Coastguard Worker size_t length;
1365*d57664e9SAndroid Build Coastguard Worker const char16_t* attr = block.getAttributeName(i, &length);
1366*d57664e9SAndroid Build Coastguard Worker if (strcmp16(attr, name16.c_str()) == 0) {
1367*d57664e9SAndroid Build Coastguard Worker name = String16(block.getAttributeStringValue(i, &length));
1368*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(attr, translatable16.c_str()) == 0) {
1369*d57664e9SAndroid Build Coastguard Worker translatable = String16(block.getAttributeStringValue(i, &length));
1370*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(attr, formatted16.c_str()) == 0) {
1371*d57664e9SAndroid Build Coastguard Worker formatted = String16(block.getAttributeStringValue(i, &length));
1372*d57664e9SAndroid Build Coastguard Worker }
1373*d57664e9SAndroid Build Coastguard Worker }
1374*d57664e9SAndroid Build Coastguard Worker
1375*d57664e9SAndroid Build Coastguard Worker if (name.size() > 0) {
1376*d57664e9SAndroid Build Coastguard Worker if (locale.size() == 0) {
1377*d57664e9SAndroid Build Coastguard Worker outTable->addDefaultLocalization(name);
1378*d57664e9SAndroid Build Coastguard Worker }
1379*d57664e9SAndroid Build Coastguard Worker if (translatable == false16) {
1380*d57664e9SAndroid Build Coastguard Worker curIsFormatted = false;
1381*d57664e9SAndroid Build Coastguard Worker // Untranslatable strings must only exist in the default [empty] locale
1382*d57664e9SAndroid Build Coastguard Worker if (locale.size() > 0) {
1383*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
1384*d57664e9SAndroid Build Coastguard Worker "string '%s' marked untranslatable but exists in locale '%s'\n",
1385*d57664e9SAndroid Build Coastguard Worker String8(name).c_str(),
1386*d57664e9SAndroid Build Coastguard Worker locale.c_str());
1387*d57664e9SAndroid Build Coastguard Worker // hasErrors = localHasErrors = true;
1388*d57664e9SAndroid Build Coastguard Worker } else {
1389*d57664e9SAndroid Build Coastguard Worker // Intentionally empty block:
1390*d57664e9SAndroid Build Coastguard Worker //
1391*d57664e9SAndroid Build Coastguard Worker // Don't add untranslatable strings to the localization table; that
1392*d57664e9SAndroid Build Coastguard Worker // way if we later see localizations of them, they'll be flagged as
1393*d57664e9SAndroid Build Coastguard Worker // having no default translation.
1394*d57664e9SAndroid Build Coastguard Worker }
1395*d57664e9SAndroid Build Coastguard Worker } else {
1396*d57664e9SAndroid Build Coastguard Worker outTable->addLocalization(
1397*d57664e9SAndroid Build Coastguard Worker name,
1398*d57664e9SAndroid Build Coastguard Worker locale,
1399*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()));
1400*d57664e9SAndroid Build Coastguard Worker }
1401*d57664e9SAndroid Build Coastguard Worker
1402*d57664e9SAndroid Build Coastguard Worker if (formatted == false16) {
1403*d57664e9SAndroid Build Coastguard Worker curIsFormatted = false;
1404*d57664e9SAndroid Build Coastguard Worker }
1405*d57664e9SAndroid Build Coastguard Worker }
1406*d57664e9SAndroid Build Coastguard Worker
1407*d57664e9SAndroid Build Coastguard Worker curTag = &string16;
1408*d57664e9SAndroid Build Coastguard Worker curType = string16;
1409*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
1410*d57664e9SAndroid Build Coastguard Worker curIsStyled = true;
1411*d57664e9SAndroid Build Coastguard Worker curIsPseudolocalizable = fileIsTranslatable && (translatable != false16);
1412*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), drawable16.c_str()) == 0) {
1413*d57664e9SAndroid Build Coastguard Worker curTag = &drawable16;
1414*d57664e9SAndroid Build Coastguard Worker curType = drawable16;
1415*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
1416*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), color16.c_str()) == 0) {
1417*d57664e9SAndroid Build Coastguard Worker curTag = &color16;
1418*d57664e9SAndroid Build Coastguard Worker curType = color16;
1419*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
1420*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), bool16.c_str()) == 0) {
1421*d57664e9SAndroid Build Coastguard Worker curTag = &bool16;
1422*d57664e9SAndroid Build Coastguard Worker curType = bool16;
1423*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_BOOLEAN;
1424*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), integer16.c_str()) == 0) {
1425*d57664e9SAndroid Build Coastguard Worker curTag = &integer16;
1426*d57664e9SAndroid Build Coastguard Worker curType = integer16;
1427*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
1428*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), dimen16.c_str()) == 0) {
1429*d57664e9SAndroid Build Coastguard Worker curTag = &dimen16;
1430*d57664e9SAndroid Build Coastguard Worker curType = dimen16;
1431*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_DIMENSION;
1432*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), fraction16.c_str()) == 0) {
1433*d57664e9SAndroid Build Coastguard Worker curTag = &fraction16;
1434*d57664e9SAndroid Build Coastguard Worker curType = fraction16;
1435*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_FRACTION;
1436*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), bag16.c_str()) == 0) {
1437*d57664e9SAndroid Build Coastguard Worker curTag = &bag16;
1438*d57664e9SAndroid Build Coastguard Worker curIsBag = true;
1439*d57664e9SAndroid Build Coastguard Worker ssize_t attri = block.indexOfAttribute(NULL, "type");
1440*d57664e9SAndroid Build Coastguard Worker if (attri >= 0) {
1441*d57664e9SAndroid Build Coastguard Worker curType = String16(block.getAttributeStringValue(attri, &len));
1442*d57664e9SAndroid Build Coastguard Worker } else {
1443*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1444*d57664e9SAndroid Build Coastguard Worker "A 'type' attribute is required for <bag>\n");
1445*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1446*d57664e9SAndroid Build Coastguard Worker }
1447*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), style16.c_str()) == 0) {
1448*d57664e9SAndroid Build Coastguard Worker curTag = &style16;
1449*d57664e9SAndroid Build Coastguard Worker curType = style16;
1450*d57664e9SAndroid Build Coastguard Worker curIsBag = true;
1451*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), plurals16.c_str()) == 0) {
1452*d57664e9SAndroid Build Coastguard Worker curTag = &plurals16;
1453*d57664e9SAndroid Build Coastguard Worker curType = plurals16;
1454*d57664e9SAndroid Build Coastguard Worker curIsBag = true;
1455*d57664e9SAndroid Build Coastguard Worker curIsPseudolocalizable = fileIsTranslatable;
1456*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), array16.c_str()) == 0) {
1457*d57664e9SAndroid Build Coastguard Worker curTag = &array16;
1458*d57664e9SAndroid Build Coastguard Worker curType = array16;
1459*d57664e9SAndroid Build Coastguard Worker curIsBag = true;
1460*d57664e9SAndroid Build Coastguard Worker curIsBagReplaceOnOverwrite = true;
1461*d57664e9SAndroid Build Coastguard Worker ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
1462*d57664e9SAndroid Build Coastguard Worker if (formatIdx >= 0) {
1463*d57664e9SAndroid Build Coastguard Worker String16 formatStr = String16(block.getAttributeStringValue(
1464*d57664e9SAndroid Build Coastguard Worker formatIdx, &len));
1465*d57664e9SAndroid Build Coastguard Worker curFormat = parse_flags(formatStr.c_str(), formatStr.size(),
1466*d57664e9SAndroid Build Coastguard Worker gFormatFlags);
1467*d57664e9SAndroid Build Coastguard Worker if (curFormat == 0) {
1468*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1469*d57664e9SAndroid Build Coastguard Worker "Tag <array> 'format' attribute value \"%s\" not valid\n",
1470*d57664e9SAndroid Build Coastguard Worker String8(formatStr).c_str());
1471*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1472*d57664e9SAndroid Build Coastguard Worker }
1473*d57664e9SAndroid Build Coastguard Worker }
1474*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), string_array16.c_str()) == 0) {
1475*d57664e9SAndroid Build Coastguard Worker // Check whether these strings need valid formats.
1476*d57664e9SAndroid Build Coastguard Worker // (simplified form of what string16 does above)
1477*d57664e9SAndroid Build Coastguard Worker bool isTranslatable = false;
1478*d57664e9SAndroid Build Coastguard Worker size_t n = block.getAttributeCount();
1479*d57664e9SAndroid Build Coastguard Worker
1480*d57664e9SAndroid Build Coastguard Worker // Pseudolocalizable by default, unless this string array isn't
1481*d57664e9SAndroid Build Coastguard Worker // translatable.
1482*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < n; i++) {
1483*d57664e9SAndroid Build Coastguard Worker size_t length;
1484*d57664e9SAndroid Build Coastguard Worker const char16_t* attr = block.getAttributeName(i, &length);
1485*d57664e9SAndroid Build Coastguard Worker if (strcmp16(attr, formatted16.c_str()) == 0) {
1486*d57664e9SAndroid Build Coastguard Worker const char16_t* value = block.getAttributeStringValue(i, &length);
1487*d57664e9SAndroid Build Coastguard Worker if (strcmp16(value, false16.c_str()) == 0) {
1488*d57664e9SAndroid Build Coastguard Worker curIsFormatted = false;
1489*d57664e9SAndroid Build Coastguard Worker }
1490*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(attr, translatable16.c_str()) == 0) {
1491*d57664e9SAndroid Build Coastguard Worker const char16_t* value = block.getAttributeStringValue(i, &length);
1492*d57664e9SAndroid Build Coastguard Worker if (strcmp16(value, false16.c_str()) == 0) {
1493*d57664e9SAndroid Build Coastguard Worker isTranslatable = false;
1494*d57664e9SAndroid Build Coastguard Worker }
1495*d57664e9SAndroid Build Coastguard Worker }
1496*d57664e9SAndroid Build Coastguard Worker }
1497*d57664e9SAndroid Build Coastguard Worker
1498*d57664e9SAndroid Build Coastguard Worker curTag = &string_array16;
1499*d57664e9SAndroid Build Coastguard Worker curType = array16;
1500*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
1501*d57664e9SAndroid Build Coastguard Worker curIsBag = true;
1502*d57664e9SAndroid Build Coastguard Worker curIsBagReplaceOnOverwrite = true;
1503*d57664e9SAndroid Build Coastguard Worker curIsPseudolocalizable = isTranslatable && fileIsTranslatable;
1504*d57664e9SAndroid Build Coastguard Worker } else if (strcmp16(block.getElementName(&len), integer_array16.c_str()) == 0) {
1505*d57664e9SAndroid Build Coastguard Worker curTag = &integer_array16;
1506*d57664e9SAndroid Build Coastguard Worker curType = array16;
1507*d57664e9SAndroid Build Coastguard Worker curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
1508*d57664e9SAndroid Build Coastguard Worker curIsBag = true;
1509*d57664e9SAndroid Build Coastguard Worker curIsBagReplaceOnOverwrite = true;
1510*d57664e9SAndroid Build Coastguard Worker } else {
1511*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1512*d57664e9SAndroid Build Coastguard Worker "Found tag %s where item is expected\n",
1513*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str());
1514*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1515*d57664e9SAndroid Build Coastguard Worker }
1516*d57664e9SAndroid Build Coastguard Worker
1517*d57664e9SAndroid Build Coastguard Worker String16 ident;
1518*d57664e9SAndroid Build Coastguard Worker ssize_t identIdx = block.indexOfAttribute(NULL, "name");
1519*d57664e9SAndroid Build Coastguard Worker if (identIdx >= 0) {
1520*d57664e9SAndroid Build Coastguard Worker ident = String16(block.getAttributeStringValue(identIdx, &len));
1521*d57664e9SAndroid Build Coastguard Worker } else {
1522*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1523*d57664e9SAndroid Build Coastguard Worker "A 'name' attribute is required for <%s>\n",
1524*d57664e9SAndroid Build Coastguard Worker String8(*curTag).c_str());
1525*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1526*d57664e9SAndroid Build Coastguard Worker }
1527*d57664e9SAndroid Build Coastguard Worker
1528*d57664e9SAndroid Build Coastguard Worker String16 product;
1529*d57664e9SAndroid Build Coastguard Worker identIdx = block.indexOfAttribute(NULL, "product");
1530*d57664e9SAndroid Build Coastguard Worker if (identIdx >= 0) {
1531*d57664e9SAndroid Build Coastguard Worker product = String16(block.getAttributeStringValue(identIdx, &len));
1532*d57664e9SAndroid Build Coastguard Worker }
1533*d57664e9SAndroid Build Coastguard Worker
1534*d57664e9SAndroid Build Coastguard Worker String16 comment(block.getComment(&len) ? block.getComment(&len) : nulStr);
1535*d57664e9SAndroid Build Coastguard Worker
1536*d57664e9SAndroid Build Coastguard Worker if (curIsBag) {
1537*d57664e9SAndroid Build Coastguard Worker // Figure out the parent of this bag...
1538*d57664e9SAndroid Build Coastguard Worker String16 parentIdent;
1539*d57664e9SAndroid Build Coastguard Worker ssize_t parentIdentIdx = block.indexOfAttribute(NULL, "parent");
1540*d57664e9SAndroid Build Coastguard Worker if (parentIdentIdx >= 0) {
1541*d57664e9SAndroid Build Coastguard Worker parentIdent = String16(block.getAttributeStringValue(parentIdentIdx, &len));
1542*d57664e9SAndroid Build Coastguard Worker } else {
1543*d57664e9SAndroid Build Coastguard Worker ssize_t sep = ident.findLast('.');
1544*d57664e9SAndroid Build Coastguard Worker if (sep >= 0) {
1545*d57664e9SAndroid Build Coastguard Worker parentIdent = String16(ident, sep);
1546*d57664e9SAndroid Build Coastguard Worker }
1547*d57664e9SAndroid Build Coastguard Worker }
1548*d57664e9SAndroid Build Coastguard Worker
1549*d57664e9SAndroid Build Coastguard Worker if (!localHasErrors) {
1550*d57664e9SAndroid Build Coastguard Worker err = outTable->startBag(SourcePos(in->getPrintableSource(),
1551*d57664e9SAndroid Build Coastguard Worker block.getLineNumber()), myPackage, curType, ident,
1552*d57664e9SAndroid Build Coastguard Worker parentIdent, &curParams,
1553*d57664e9SAndroid Build Coastguard Worker overwrite, curIsBagReplaceOnOverwrite);
1554*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1555*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1556*d57664e9SAndroid Build Coastguard Worker }
1557*d57664e9SAndroid Build Coastguard Worker }
1558*d57664e9SAndroid Build Coastguard Worker
1559*d57664e9SAndroid Build Coastguard Worker ssize_t elmIndex = 0;
1560*d57664e9SAndroid Build Coastguard Worker char elmIndexStr[14];
1561*d57664e9SAndroid Build Coastguard Worker while ((code=block.next()) != ResXMLTree::END_DOCUMENT
1562*d57664e9SAndroid Build Coastguard Worker && code != ResXMLTree::BAD_DOCUMENT) {
1563*d57664e9SAndroid Build Coastguard Worker
1564*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::START_TAG) {
1565*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), item16.c_str()) != 0) {
1566*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1567*d57664e9SAndroid Build Coastguard Worker "Tag <%s> can not appear inside <%s>, only <item>\n",
1568*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str(),
1569*d57664e9SAndroid Build Coastguard Worker String8(*curTag).c_str());
1570*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1571*d57664e9SAndroid Build Coastguard Worker }
1572*d57664e9SAndroid Build Coastguard Worker
1573*d57664e9SAndroid Build Coastguard Worker String16 itemIdent;
1574*d57664e9SAndroid Build Coastguard Worker if (curType == array16) {
1575*d57664e9SAndroid Build Coastguard Worker sprintf(elmIndexStr, "^index_%d", (int)elmIndex++);
1576*d57664e9SAndroid Build Coastguard Worker itemIdent = String16(elmIndexStr);
1577*d57664e9SAndroid Build Coastguard Worker } else if (curType == plurals16) {
1578*d57664e9SAndroid Build Coastguard Worker ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "quantity");
1579*d57664e9SAndroid Build Coastguard Worker if (itemIdentIdx >= 0) {
1580*d57664e9SAndroid Build Coastguard Worker String16 quantity16(block.getAttributeStringValue(itemIdentIdx, &len));
1581*d57664e9SAndroid Build Coastguard Worker if (quantity16 == other16) {
1582*d57664e9SAndroid Build Coastguard Worker itemIdent = quantityOther16;
1583*d57664e9SAndroid Build Coastguard Worker }
1584*d57664e9SAndroid Build Coastguard Worker else if (quantity16 == zero16) {
1585*d57664e9SAndroid Build Coastguard Worker itemIdent = quantityZero16;
1586*d57664e9SAndroid Build Coastguard Worker }
1587*d57664e9SAndroid Build Coastguard Worker else if (quantity16 == one16) {
1588*d57664e9SAndroid Build Coastguard Worker itemIdent = quantityOne16;
1589*d57664e9SAndroid Build Coastguard Worker }
1590*d57664e9SAndroid Build Coastguard Worker else if (quantity16 == two16) {
1591*d57664e9SAndroid Build Coastguard Worker itemIdent = quantityTwo16;
1592*d57664e9SAndroid Build Coastguard Worker }
1593*d57664e9SAndroid Build Coastguard Worker else if (quantity16 == few16) {
1594*d57664e9SAndroid Build Coastguard Worker itemIdent = quantityFew16;
1595*d57664e9SAndroid Build Coastguard Worker }
1596*d57664e9SAndroid Build Coastguard Worker else if (quantity16 == many16) {
1597*d57664e9SAndroid Build Coastguard Worker itemIdent = quantityMany16;
1598*d57664e9SAndroid Build Coastguard Worker }
1599*d57664e9SAndroid Build Coastguard Worker else {
1600*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1601*d57664e9SAndroid Build Coastguard Worker "Illegal 'quantity' attribute is <item> inside <plurals>\n");
1602*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1603*d57664e9SAndroid Build Coastguard Worker }
1604*d57664e9SAndroid Build Coastguard Worker } else {
1605*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1606*d57664e9SAndroid Build Coastguard Worker "A 'quantity' attribute is required for <item> inside <plurals>\n");
1607*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1608*d57664e9SAndroid Build Coastguard Worker }
1609*d57664e9SAndroid Build Coastguard Worker } else {
1610*d57664e9SAndroid Build Coastguard Worker ssize_t itemIdentIdx = block.indexOfAttribute(NULL, "name");
1611*d57664e9SAndroid Build Coastguard Worker if (itemIdentIdx >= 0) {
1612*d57664e9SAndroid Build Coastguard Worker itemIdent = String16(block.getAttributeStringValue(itemIdentIdx, &len));
1613*d57664e9SAndroid Build Coastguard Worker } else {
1614*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1615*d57664e9SAndroid Build Coastguard Worker "A 'name' attribute is required for <item>\n");
1616*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1617*d57664e9SAndroid Build Coastguard Worker }
1618*d57664e9SAndroid Build Coastguard Worker }
1619*d57664e9SAndroid Build Coastguard Worker
1620*d57664e9SAndroid Build Coastguard Worker ResXMLParser::ResXMLPosition parserPosition;
1621*d57664e9SAndroid Build Coastguard Worker block.getPosition(&parserPosition);
1622*d57664e9SAndroid Build Coastguard Worker
1623*d57664e9SAndroid Build Coastguard Worker err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
1624*d57664e9SAndroid Build Coastguard Worker ident, parentIdent, itemIdent, curFormat, curIsFormatted,
1625*d57664e9SAndroid Build Coastguard Worker product, NO_PSEUDOLOCALIZATION, overwrite, outTable);
1626*d57664e9SAndroid Build Coastguard Worker if (err == NO_ERROR) {
1627*d57664e9SAndroid Build Coastguard Worker if (curIsPseudolocalizable && localeIsDefined(curParams)
1628*d57664e9SAndroid Build Coastguard Worker && bundle->getPseudolocalize() > 0) {
1629*d57664e9SAndroid Build Coastguard Worker // pseudolocalize here
1630*d57664e9SAndroid Build Coastguard Worker if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) ==
1631*d57664e9SAndroid Build Coastguard Worker PSEUDO_ACCENTED) {
1632*d57664e9SAndroid Build Coastguard Worker block.setPosition(parserPosition);
1633*d57664e9SAndroid Build Coastguard Worker err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
1634*d57664e9SAndroid Build Coastguard Worker curType, ident, parentIdent, itemIdent, curFormat,
1635*d57664e9SAndroid Build Coastguard Worker curIsFormatted, product, PSEUDO_ACCENTED,
1636*d57664e9SAndroid Build Coastguard Worker overwrite, outTable);
1637*d57664e9SAndroid Build Coastguard Worker }
1638*d57664e9SAndroid Build Coastguard Worker if ((PSEUDO_BIDI & bundle->getPseudolocalize()) ==
1639*d57664e9SAndroid Build Coastguard Worker PSEUDO_BIDI) {
1640*d57664e9SAndroid Build Coastguard Worker block.setPosition(parserPosition);
1641*d57664e9SAndroid Build Coastguard Worker err = parseAndAddBag(bundle, in, &block, pseudoBidiParams, myPackage,
1642*d57664e9SAndroid Build Coastguard Worker curType, ident, parentIdent, itemIdent, curFormat,
1643*d57664e9SAndroid Build Coastguard Worker curIsFormatted, product, PSEUDO_BIDI,
1644*d57664e9SAndroid Build Coastguard Worker overwrite, outTable);
1645*d57664e9SAndroid Build Coastguard Worker }
1646*d57664e9SAndroid Build Coastguard Worker }
1647*d57664e9SAndroid Build Coastguard Worker }
1648*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1649*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1650*d57664e9SAndroid Build Coastguard Worker }
1651*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::END_TAG) {
1652*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), curTag->c_str()) != 0) {
1653*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1654*d57664e9SAndroid Build Coastguard Worker "Found tag </%s> where </%s> is expected\n",
1655*d57664e9SAndroid Build Coastguard Worker String8(block.getElementName(&len)).c_str(),
1656*d57664e9SAndroid Build Coastguard Worker String8(*curTag).c_str());
1657*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1658*d57664e9SAndroid Build Coastguard Worker }
1659*d57664e9SAndroid Build Coastguard Worker break;
1660*d57664e9SAndroid Build Coastguard Worker }
1661*d57664e9SAndroid Build Coastguard Worker }
1662*d57664e9SAndroid Build Coastguard Worker } else {
1663*d57664e9SAndroid Build Coastguard Worker ResXMLParser::ResXMLPosition parserPosition;
1664*d57664e9SAndroid Build Coastguard Worker block.getPosition(&parserPosition);
1665*d57664e9SAndroid Build Coastguard Worker
1666*d57664e9SAndroid Build Coastguard Worker err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
1667*d57664e9SAndroid Build Coastguard Worker *curTag, curIsStyled, curFormat, curIsFormatted,
1668*d57664e9SAndroid Build Coastguard Worker product, NO_PSEUDOLOCALIZATION, overwrite, &skippedResourceNames, outTable);
1669*d57664e9SAndroid Build Coastguard Worker
1670*d57664e9SAndroid Build Coastguard Worker if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
1671*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1672*d57664e9SAndroid Build Coastguard Worker }
1673*d57664e9SAndroid Build Coastguard Worker else if (err == NO_ERROR) {
1674*d57664e9SAndroid Build Coastguard Worker if (curType == string16 && !curParams.language[0] && !curParams.country[0]) {
1675*d57664e9SAndroid Build Coastguard Worker outTable->addDefaultLocalization(curName);
1676*d57664e9SAndroid Build Coastguard Worker }
1677*d57664e9SAndroid Build Coastguard Worker if (curIsPseudolocalizable && localeIsDefined(curParams)
1678*d57664e9SAndroid Build Coastguard Worker && bundle->getPseudolocalize() > 0) {
1679*d57664e9SAndroid Build Coastguard Worker // pseudolocalize here
1680*d57664e9SAndroid Build Coastguard Worker if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) ==
1681*d57664e9SAndroid Build Coastguard Worker PSEUDO_ACCENTED) {
1682*d57664e9SAndroid Build Coastguard Worker block.setPosition(parserPosition);
1683*d57664e9SAndroid Build Coastguard Worker err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
1684*d57664e9SAndroid Build Coastguard Worker ident, *curTag, curIsStyled, curFormat,
1685*d57664e9SAndroid Build Coastguard Worker curIsFormatted, product,
1686*d57664e9SAndroid Build Coastguard Worker PSEUDO_ACCENTED, overwrite, &skippedResourceNames, outTable);
1687*d57664e9SAndroid Build Coastguard Worker }
1688*d57664e9SAndroid Build Coastguard Worker if ((PSEUDO_BIDI & bundle->getPseudolocalize()) ==
1689*d57664e9SAndroid Build Coastguard Worker PSEUDO_BIDI) {
1690*d57664e9SAndroid Build Coastguard Worker block.setPosition(parserPosition);
1691*d57664e9SAndroid Build Coastguard Worker err = parseAndAddEntry(bundle, in, &block, pseudoBidiParams,
1692*d57664e9SAndroid Build Coastguard Worker myPackage, curType, ident, *curTag, curIsStyled, curFormat,
1693*d57664e9SAndroid Build Coastguard Worker curIsFormatted, product,
1694*d57664e9SAndroid Build Coastguard Worker PSEUDO_BIDI, overwrite, &skippedResourceNames, outTable);
1695*d57664e9SAndroid Build Coastguard Worker }
1696*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1697*d57664e9SAndroid Build Coastguard Worker hasErrors = localHasErrors = true;
1698*d57664e9SAndroid Build Coastguard Worker }
1699*d57664e9SAndroid Build Coastguard Worker }
1700*d57664e9SAndroid Build Coastguard Worker }
1701*d57664e9SAndroid Build Coastguard Worker }
1702*d57664e9SAndroid Build Coastguard Worker
1703*d57664e9SAndroid Build Coastguard Worker #if 0
1704*d57664e9SAndroid Build Coastguard Worker if (comment.size() > 0) {
1705*d57664e9SAndroid Build Coastguard Worker printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).c_str(),
1706*d57664e9SAndroid Build Coastguard Worker String8(curType).c_str(), String8(ident).c_str(),
1707*d57664e9SAndroid Build Coastguard Worker String8(comment).c_str());
1708*d57664e9SAndroid Build Coastguard Worker }
1709*d57664e9SAndroid Build Coastguard Worker #endif
1710*d57664e9SAndroid Build Coastguard Worker if (!localHasErrors) {
1711*d57664e9SAndroid Build Coastguard Worker outTable->appendComment(myPackage, curType, ident, comment, false);
1712*d57664e9SAndroid Build Coastguard Worker }
1713*d57664e9SAndroid Build Coastguard Worker }
1714*d57664e9SAndroid Build Coastguard Worker else if (code == ResXMLTree::END_TAG) {
1715*d57664e9SAndroid Build Coastguard Worker if (strcmp16(block.getElementName(&len), resources16.c_str()) != 0) {
1716*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1717*d57664e9SAndroid Build Coastguard Worker "Unexpected end tag %s\n", String8(block.getElementName(&len)).c_str());
1718*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1719*d57664e9SAndroid Build Coastguard Worker }
1720*d57664e9SAndroid Build Coastguard Worker }
1721*d57664e9SAndroid Build Coastguard Worker else if (code == ResXMLTree::START_NAMESPACE || code == ResXMLTree::END_NAMESPACE) {
1722*d57664e9SAndroid Build Coastguard Worker }
1723*d57664e9SAndroid Build Coastguard Worker else if (code == ResXMLTree::TEXT) {
1724*d57664e9SAndroid Build Coastguard Worker if (isWhitespace(block.getText(&len))) {
1725*d57664e9SAndroid Build Coastguard Worker continue;
1726*d57664e9SAndroid Build Coastguard Worker }
1727*d57664e9SAndroid Build Coastguard Worker SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
1728*d57664e9SAndroid Build Coastguard Worker "Found text \"%s\" where item tag is expected\n",
1729*d57664e9SAndroid Build Coastguard Worker String8(block.getText(&len)).c_str());
1730*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1731*d57664e9SAndroid Build Coastguard Worker }
1732*d57664e9SAndroid Build Coastguard Worker }
1733*d57664e9SAndroid Build Coastguard Worker
1734*d57664e9SAndroid Build Coastguard Worker // For every resource defined, there must be exist one variant with a product attribute
1735*d57664e9SAndroid Build Coastguard Worker // set to 'default' (or no product attribute at all).
1736*d57664e9SAndroid Build Coastguard Worker // We check to see that for every resource that was ignored because of a mismatched
1737*d57664e9SAndroid Build Coastguard Worker // product attribute, some product variant of that resource was processed.
1738*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < skippedResourceNames.size(); i++) {
1739*d57664e9SAndroid Build Coastguard Worker if (skippedResourceNames[i]) {
1740*d57664e9SAndroid Build Coastguard Worker const type_ident_pair_t& p = skippedResourceNames.keyAt(i);
1741*d57664e9SAndroid Build Coastguard Worker if (!outTable->hasBagOrEntry(myPackage, p.type, p.ident)) {
1742*d57664e9SAndroid Build Coastguard Worker const char* bundleProduct =
1743*d57664e9SAndroid Build Coastguard Worker (bundle->getProduct() == NULL) ? "" : bundle->getProduct();
1744*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "In resource file %s: %s\n",
1745*d57664e9SAndroid Build Coastguard Worker in->getPrintableSource().c_str(),
1746*d57664e9SAndroid Build Coastguard Worker curParams.toString().c_str());
1747*d57664e9SAndroid Build Coastguard Worker
1748*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "\t%s '%s' does not match product %s.\n"
1749*d57664e9SAndroid Build Coastguard Worker "\tYou may have forgotten to include a 'default' product variant"
1750*d57664e9SAndroid Build Coastguard Worker " of the resource.\n",
1751*d57664e9SAndroid Build Coastguard Worker String8(p.type).c_str(), String8(p.ident).c_str(),
1752*d57664e9SAndroid Build Coastguard Worker bundleProduct[0] == 0 ? "default" : bundleProduct);
1753*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1754*d57664e9SAndroid Build Coastguard Worker }
1755*d57664e9SAndroid Build Coastguard Worker }
1756*d57664e9SAndroid Build Coastguard Worker }
1757*d57664e9SAndroid Build Coastguard Worker
1758*d57664e9SAndroid Build Coastguard Worker return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
1759*d57664e9SAndroid Build Coastguard Worker }
1760*d57664e9SAndroid Build Coastguard Worker
ResourceTable(Bundle * bundle,const String16 & assetsPackage,ResourceTable::PackageType type)1761*d57664e9SAndroid Build Coastguard Worker ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type)
1762*d57664e9SAndroid Build Coastguard Worker : mAssetsPackage(assetsPackage)
1763*d57664e9SAndroid Build Coastguard Worker , mPackageType(type)
1764*d57664e9SAndroid Build Coastguard Worker , mTypeIdOffset(0)
1765*d57664e9SAndroid Build Coastguard Worker , mNumLocal(0)
1766*d57664e9SAndroid Build Coastguard Worker , mBundle(bundle)
1767*d57664e9SAndroid Build Coastguard Worker {
1768*d57664e9SAndroid Build Coastguard Worker ssize_t packageId = -1;
1769*d57664e9SAndroid Build Coastguard Worker switch (mPackageType) {
1770*d57664e9SAndroid Build Coastguard Worker case App:
1771*d57664e9SAndroid Build Coastguard Worker case AppFeature:
1772*d57664e9SAndroid Build Coastguard Worker packageId = 0x7f;
1773*d57664e9SAndroid Build Coastguard Worker break;
1774*d57664e9SAndroid Build Coastguard Worker
1775*d57664e9SAndroid Build Coastguard Worker case System:
1776*d57664e9SAndroid Build Coastguard Worker packageId = 0x01;
1777*d57664e9SAndroid Build Coastguard Worker break;
1778*d57664e9SAndroid Build Coastguard Worker
1779*d57664e9SAndroid Build Coastguard Worker case SharedLibrary:
1780*d57664e9SAndroid Build Coastguard Worker packageId = 0x00;
1781*d57664e9SAndroid Build Coastguard Worker break;
1782*d57664e9SAndroid Build Coastguard Worker
1783*d57664e9SAndroid Build Coastguard Worker default:
1784*d57664e9SAndroid Build Coastguard Worker assert(0);
1785*d57664e9SAndroid Build Coastguard Worker break;
1786*d57664e9SAndroid Build Coastguard Worker }
1787*d57664e9SAndroid Build Coastguard Worker sp<Package> package = new Package(mAssetsPackage, packageId);
1788*d57664e9SAndroid Build Coastguard Worker mPackages.add(assetsPackage, package);
1789*d57664e9SAndroid Build Coastguard Worker mOrderedPackages.add(package);
1790*d57664e9SAndroid Build Coastguard Worker
1791*d57664e9SAndroid Build Coastguard Worker // Every resource table always has one first entry, the bag attributes.
1792*d57664e9SAndroid Build Coastguard Worker const SourcePos unknown(String8("????"), 0);
1793*d57664e9SAndroid Build Coastguard Worker getType(mAssetsPackage, String16("attr"), unknown);
1794*d57664e9SAndroid Build Coastguard Worker }
1795*d57664e9SAndroid Build Coastguard Worker
findLargestTypeIdForPackage(const ResTable & table,const String16 & packageName)1796*d57664e9SAndroid Build Coastguard Worker static uint32_t findLargestTypeIdForPackage(const ResTable& table, const String16& packageName) {
1797*d57664e9SAndroid Build Coastguard Worker const size_t basePackageCount = table.getBasePackageCount();
1798*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < basePackageCount; i++) {
1799*d57664e9SAndroid Build Coastguard Worker if (packageName == table.getBasePackageName(i)) {
1800*d57664e9SAndroid Build Coastguard Worker return table.getLastTypeIdForPackage(i);
1801*d57664e9SAndroid Build Coastguard Worker }
1802*d57664e9SAndroid Build Coastguard Worker }
1803*d57664e9SAndroid Build Coastguard Worker return 0;
1804*d57664e9SAndroid Build Coastguard Worker }
1805*d57664e9SAndroid Build Coastguard Worker
addIncludedResources(Bundle * bundle,const sp<AaptAssets> & assets)1806*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets)
1807*d57664e9SAndroid Build Coastguard Worker {
1808*d57664e9SAndroid Build Coastguard Worker status_t err = assets->buildIncludedResources(bundle);
1809*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1810*d57664e9SAndroid Build Coastguard Worker return err;
1811*d57664e9SAndroid Build Coastguard Worker }
1812*d57664e9SAndroid Build Coastguard Worker
1813*d57664e9SAndroid Build Coastguard Worker mAssets = assets;
1814*d57664e9SAndroid Build Coastguard Worker mTypeIdOffset = findLargestTypeIdForPackage(assets->getIncludedResources(), mAssetsPackage);
1815*d57664e9SAndroid Build Coastguard Worker
1816*d57664e9SAndroid Build Coastguard Worker const String8& featureAfter = bundle->getFeatureAfterPackage();
1817*d57664e9SAndroid Build Coastguard Worker if (!featureAfter.empty()) {
1818*d57664e9SAndroid Build Coastguard Worker AssetManager featureAssetManager;
1819*d57664e9SAndroid Build Coastguard Worker if (!featureAssetManager.addAssetPath(featureAfter, NULL)) {
1820*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: Feature package '%s' not found.\n",
1821*d57664e9SAndroid Build Coastguard Worker featureAfter.c_str());
1822*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1823*d57664e9SAndroid Build Coastguard Worker }
1824*d57664e9SAndroid Build Coastguard Worker
1825*d57664e9SAndroid Build Coastguard Worker const ResTable& featureTable = featureAssetManager.getResources(false);
1826*d57664e9SAndroid Build Coastguard Worker mTypeIdOffset = std::max(mTypeIdOffset,
1827*d57664e9SAndroid Build Coastguard Worker findLargestTypeIdForPackage(featureTable, mAssetsPackage));
1828*d57664e9SAndroid Build Coastguard Worker }
1829*d57664e9SAndroid Build Coastguard Worker
1830*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1831*d57664e9SAndroid Build Coastguard Worker }
1832*d57664e9SAndroid Build Coastguard Worker
addPublic(const SourcePos & sourcePos,const String16 & package,const String16 & type,const String16 & name,const uint32_t ident)1833*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::addPublic(const SourcePos& sourcePos,
1834*d57664e9SAndroid Build Coastguard Worker const String16& package,
1835*d57664e9SAndroid Build Coastguard Worker const String16& type,
1836*d57664e9SAndroid Build Coastguard Worker const String16& name,
1837*d57664e9SAndroid Build Coastguard Worker const uint32_t ident)
1838*d57664e9SAndroid Build Coastguard Worker {
1839*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
1840*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
1841*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
1842*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
1843*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
1844*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Error declaring public resource %s/%s for included package %s\n",
1845*d57664e9SAndroid Build Coastguard Worker String8(type).c_str(), String8(name).c_str(),
1846*d57664e9SAndroid Build Coastguard Worker String8(package).c_str());
1847*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1848*d57664e9SAndroid Build Coastguard Worker }
1849*d57664e9SAndroid Build Coastguard Worker
1850*d57664e9SAndroid Build Coastguard Worker sp<Type> t = getType(package, type, sourcePos);
1851*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
1852*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1853*d57664e9SAndroid Build Coastguard Worker }
1854*d57664e9SAndroid Build Coastguard Worker return t->addPublic(sourcePos, name, ident);
1855*d57664e9SAndroid Build Coastguard Worker }
1856*d57664e9SAndroid Build Coastguard Worker
addEntry(const SourcePos & sourcePos,const String16 & package,const String16 & type,const String16 & name,const String16 & value,const Vector<StringPool::entry_style_span> * style,const ResTable_config * params,const bool doSetIndex,const int32_t format,const bool overwrite)1857*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::addEntry(const SourcePos& sourcePos,
1858*d57664e9SAndroid Build Coastguard Worker const String16& package,
1859*d57664e9SAndroid Build Coastguard Worker const String16& type,
1860*d57664e9SAndroid Build Coastguard Worker const String16& name,
1861*d57664e9SAndroid Build Coastguard Worker const String16& value,
1862*d57664e9SAndroid Build Coastguard Worker const Vector<StringPool::entry_style_span>* style,
1863*d57664e9SAndroid Build Coastguard Worker const ResTable_config* params,
1864*d57664e9SAndroid Build Coastguard Worker const bool doSetIndex,
1865*d57664e9SAndroid Build Coastguard Worker const int32_t format,
1866*d57664e9SAndroid Build Coastguard Worker const bool overwrite)
1867*d57664e9SAndroid Build Coastguard Worker {
1868*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
1869*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
1870*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
1871*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
1872*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
1873*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s/%s is already defined in package %s.",
1874*d57664e9SAndroid Build Coastguard Worker String8(type).c_str(), String8(name).c_str(), String8(package).c_str());
1875*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1876*d57664e9SAndroid Build Coastguard Worker }
1877*d57664e9SAndroid Build Coastguard Worker
1878*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = getEntry(package, type, name, sourcePos, overwrite,
1879*d57664e9SAndroid Build Coastguard Worker params, doSetIndex);
1880*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
1881*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1882*d57664e9SAndroid Build Coastguard Worker }
1883*d57664e9SAndroid Build Coastguard Worker status_t err = e->setItem(sourcePos, value, style, format, overwrite);
1884*d57664e9SAndroid Build Coastguard Worker if (err == NO_ERROR) {
1885*d57664e9SAndroid Build Coastguard Worker mNumLocal++;
1886*d57664e9SAndroid Build Coastguard Worker }
1887*d57664e9SAndroid Build Coastguard Worker return err;
1888*d57664e9SAndroid Build Coastguard Worker }
1889*d57664e9SAndroid Build Coastguard Worker
startBag(const SourcePos & sourcePos,const String16 & package,const String16 & type,const String16 & name,const String16 & bagParent,const ResTable_config * params,bool overlay,bool replace,bool)1890*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::startBag(const SourcePos& sourcePos,
1891*d57664e9SAndroid Build Coastguard Worker const String16& package,
1892*d57664e9SAndroid Build Coastguard Worker const String16& type,
1893*d57664e9SAndroid Build Coastguard Worker const String16& name,
1894*d57664e9SAndroid Build Coastguard Worker const String16& bagParent,
1895*d57664e9SAndroid Build Coastguard Worker const ResTable_config* params,
1896*d57664e9SAndroid Build Coastguard Worker bool overlay,
1897*d57664e9SAndroid Build Coastguard Worker bool replace, bool /* isId */)
1898*d57664e9SAndroid Build Coastguard Worker {
1899*d57664e9SAndroid Build Coastguard Worker status_t result = NO_ERROR;
1900*d57664e9SAndroid Build Coastguard Worker
1901*d57664e9SAndroid Build Coastguard Worker // Check for adding entries in other packages... for now we do
1902*d57664e9SAndroid Build Coastguard Worker // nothing. We need to do the right thing here to support skinning.
1903*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
1904*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
1905*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
1906*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
1907*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
1908*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s/%s is already defined in package %s.",
1909*d57664e9SAndroid Build Coastguard Worker String8(type).c_str(), String8(name).c_str(), String8(package).c_str());
1910*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1911*d57664e9SAndroid Build Coastguard Worker }
1912*d57664e9SAndroid Build Coastguard Worker
1913*d57664e9SAndroid Build Coastguard Worker if (overlay && !mBundle->getAutoAddOverlay() && !hasBagOrEntry(package, type, name)) {
1914*d57664e9SAndroid Build Coastguard Worker bool canAdd = false;
1915*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
1916*d57664e9SAndroid Build Coastguard Worker if (p != NULL) {
1917*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
1918*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
1919*d57664e9SAndroid Build Coastguard Worker if (t->getCanAddEntries().indexOf(name) >= 0) {
1920*d57664e9SAndroid Build Coastguard Worker canAdd = true;
1921*d57664e9SAndroid Build Coastguard Worker }
1922*d57664e9SAndroid Build Coastguard Worker }
1923*d57664e9SAndroid Build Coastguard Worker }
1924*d57664e9SAndroid Build Coastguard Worker if (!canAdd) {
1925*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
1926*d57664e9SAndroid Build Coastguard Worker String8(name).c_str());
1927*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1928*d57664e9SAndroid Build Coastguard Worker }
1929*d57664e9SAndroid Build Coastguard Worker }
1930*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
1931*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
1932*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1933*d57664e9SAndroid Build Coastguard Worker }
1934*d57664e9SAndroid Build Coastguard Worker
1935*d57664e9SAndroid Build Coastguard Worker // If a parent is explicitly specified, set it.
1936*d57664e9SAndroid Build Coastguard Worker if (bagParent.size() > 0) {
1937*d57664e9SAndroid Build Coastguard Worker e->setParent(bagParent);
1938*d57664e9SAndroid Build Coastguard Worker }
1939*d57664e9SAndroid Build Coastguard Worker
1940*d57664e9SAndroid Build Coastguard Worker if ((result = e->makeItABag(sourcePos)) != NO_ERROR) {
1941*d57664e9SAndroid Build Coastguard Worker return result;
1942*d57664e9SAndroid Build Coastguard Worker }
1943*d57664e9SAndroid Build Coastguard Worker
1944*d57664e9SAndroid Build Coastguard Worker if (overlay && replace) {
1945*d57664e9SAndroid Build Coastguard Worker return e->emptyBag(sourcePos);
1946*d57664e9SAndroid Build Coastguard Worker }
1947*d57664e9SAndroid Build Coastguard Worker return result;
1948*d57664e9SAndroid Build Coastguard Worker }
1949*d57664e9SAndroid Build Coastguard Worker
addBag(const SourcePos & sourcePos,const String16 & package,const String16 & type,const String16 & name,const String16 & bagParent,const String16 & bagKey,const String16 & value,const Vector<StringPool::entry_style_span> * style,const ResTable_config * params,bool replace,bool isId,const int32_t format)1950*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::addBag(const SourcePos& sourcePos,
1951*d57664e9SAndroid Build Coastguard Worker const String16& package,
1952*d57664e9SAndroid Build Coastguard Worker const String16& type,
1953*d57664e9SAndroid Build Coastguard Worker const String16& name,
1954*d57664e9SAndroid Build Coastguard Worker const String16& bagParent,
1955*d57664e9SAndroid Build Coastguard Worker const String16& bagKey,
1956*d57664e9SAndroid Build Coastguard Worker const String16& value,
1957*d57664e9SAndroid Build Coastguard Worker const Vector<StringPool::entry_style_span>* style,
1958*d57664e9SAndroid Build Coastguard Worker const ResTable_config* params,
1959*d57664e9SAndroid Build Coastguard Worker bool replace, bool isId, const int32_t format)
1960*d57664e9SAndroid Build Coastguard Worker {
1961*d57664e9SAndroid Build Coastguard Worker // Check for adding entries in other packages... for now we do
1962*d57664e9SAndroid Build Coastguard Worker // nothing. We need to do the right thing here to support skinning.
1963*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
1964*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
1965*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
1966*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
1967*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
1968*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1969*d57664e9SAndroid Build Coastguard Worker }
1970*d57664e9SAndroid Build Coastguard Worker
1971*d57664e9SAndroid Build Coastguard Worker #if 0
1972*d57664e9SAndroid Build Coastguard Worker if (name == String16("left")) {
1973*d57664e9SAndroid Build Coastguard Worker printf("Adding bag left: file=%s, line=%d, type=%s\n",
1974*d57664e9SAndroid Build Coastguard Worker sourcePos.file.striing(), sourcePos.line, String8(type).c_str());
1975*d57664e9SAndroid Build Coastguard Worker }
1976*d57664e9SAndroid Build Coastguard Worker #endif
1977*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params);
1978*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
1979*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
1980*d57664e9SAndroid Build Coastguard Worker }
1981*d57664e9SAndroid Build Coastguard Worker
1982*d57664e9SAndroid Build Coastguard Worker // If a parent is explicitly specified, set it.
1983*d57664e9SAndroid Build Coastguard Worker if (bagParent.size() > 0) {
1984*d57664e9SAndroid Build Coastguard Worker e->setParent(bagParent);
1985*d57664e9SAndroid Build Coastguard Worker }
1986*d57664e9SAndroid Build Coastguard Worker
1987*d57664e9SAndroid Build Coastguard Worker const bool first = e->getBag().indexOfKey(bagKey) < 0;
1988*d57664e9SAndroid Build Coastguard Worker status_t err = e->addToBag(sourcePos, bagKey, value, style, replace, isId, format);
1989*d57664e9SAndroid Build Coastguard Worker if (err == NO_ERROR && first) {
1990*d57664e9SAndroid Build Coastguard Worker mNumLocal++;
1991*d57664e9SAndroid Build Coastguard Worker }
1992*d57664e9SAndroid Build Coastguard Worker return err;
1993*d57664e9SAndroid Build Coastguard Worker }
1994*d57664e9SAndroid Build Coastguard Worker
hasBagOrEntry(const String16 & package,const String16 & type,const String16 & name) const1995*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::hasBagOrEntry(const String16& package,
1996*d57664e9SAndroid Build Coastguard Worker const String16& type,
1997*d57664e9SAndroid Build Coastguard Worker const String16& name) const
1998*d57664e9SAndroid Build Coastguard Worker {
1999*d57664e9SAndroid Build Coastguard Worker // First look for this in the included resources...
2000*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
2001*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
2002*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
2003*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
2004*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
2005*d57664e9SAndroid Build Coastguard Worker return true;
2006*d57664e9SAndroid Build Coastguard Worker }
2007*d57664e9SAndroid Build Coastguard Worker
2008*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
2009*d57664e9SAndroid Build Coastguard Worker if (p != NULL) {
2010*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
2011*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
2012*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getConfigs().valueFor(name);
2013*d57664e9SAndroid Build Coastguard Worker if (c != NULL) return true;
2014*d57664e9SAndroid Build Coastguard Worker }
2015*d57664e9SAndroid Build Coastguard Worker }
2016*d57664e9SAndroid Build Coastguard Worker
2017*d57664e9SAndroid Build Coastguard Worker return false;
2018*d57664e9SAndroid Build Coastguard Worker }
2019*d57664e9SAndroid Build Coastguard Worker
hasBagOrEntry(const String16 & package,const String16 & type,const String16 & name,const ResTable_config & config) const2020*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::hasBagOrEntry(const String16& package,
2021*d57664e9SAndroid Build Coastguard Worker const String16& type,
2022*d57664e9SAndroid Build Coastguard Worker const String16& name,
2023*d57664e9SAndroid Build Coastguard Worker const ResTable_config& config) const
2024*d57664e9SAndroid Build Coastguard Worker {
2025*d57664e9SAndroid Build Coastguard Worker // First look for this in the included resources...
2026*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
2027*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
2028*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
2029*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
2030*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
2031*d57664e9SAndroid Build Coastguard Worker return true;
2032*d57664e9SAndroid Build Coastguard Worker }
2033*d57664e9SAndroid Build Coastguard Worker
2034*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
2035*d57664e9SAndroid Build Coastguard Worker if (p != NULL) {
2036*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
2037*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
2038*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getConfigs().valueFor(name);
2039*d57664e9SAndroid Build Coastguard Worker if (c != NULL) {
2040*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = c->getEntries().valueFor(config);
2041*d57664e9SAndroid Build Coastguard Worker if (e != NULL) {
2042*d57664e9SAndroid Build Coastguard Worker return true;
2043*d57664e9SAndroid Build Coastguard Worker }
2044*d57664e9SAndroid Build Coastguard Worker }
2045*d57664e9SAndroid Build Coastguard Worker }
2046*d57664e9SAndroid Build Coastguard Worker }
2047*d57664e9SAndroid Build Coastguard Worker
2048*d57664e9SAndroid Build Coastguard Worker return false;
2049*d57664e9SAndroid Build Coastguard Worker }
2050*d57664e9SAndroid Build Coastguard Worker
hasBagOrEntry(const String16 & ref,const String16 * defType,const String16 * defPackage)2051*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::hasBagOrEntry(const String16& ref,
2052*d57664e9SAndroid Build Coastguard Worker const String16* defType,
2053*d57664e9SAndroid Build Coastguard Worker const String16* defPackage)
2054*d57664e9SAndroid Build Coastguard Worker {
2055*d57664e9SAndroid Build Coastguard Worker String16 package, type, name;
2056*d57664e9SAndroid Build Coastguard Worker if (!ResTable::expandResourceRef(ref.c_str(), ref.size(), &package, &type, &name,
2057*d57664e9SAndroid Build Coastguard Worker defType, defPackage ? defPackage:&mAssetsPackage, NULL)) {
2058*d57664e9SAndroid Build Coastguard Worker return false;
2059*d57664e9SAndroid Build Coastguard Worker }
2060*d57664e9SAndroid Build Coastguard Worker return hasBagOrEntry(package, type, name);
2061*d57664e9SAndroid Build Coastguard Worker }
2062*d57664e9SAndroid Build Coastguard Worker
appendComment(const String16 & package,const String16 & type,const String16 & name,const String16 & comment,bool onlyIfEmpty)2063*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::appendComment(const String16& package,
2064*d57664e9SAndroid Build Coastguard Worker const String16& type,
2065*d57664e9SAndroid Build Coastguard Worker const String16& name,
2066*d57664e9SAndroid Build Coastguard Worker const String16& comment,
2067*d57664e9SAndroid Build Coastguard Worker bool onlyIfEmpty)
2068*d57664e9SAndroid Build Coastguard Worker {
2069*d57664e9SAndroid Build Coastguard Worker if (comment.size() <= 0) {
2070*d57664e9SAndroid Build Coastguard Worker return true;
2071*d57664e9SAndroid Build Coastguard Worker }
2072*d57664e9SAndroid Build Coastguard Worker
2073*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
2074*d57664e9SAndroid Build Coastguard Worker if (p != NULL) {
2075*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
2076*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
2077*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getConfigs().valueFor(name);
2078*d57664e9SAndroid Build Coastguard Worker if (c != NULL) {
2079*d57664e9SAndroid Build Coastguard Worker c->appendComment(comment, onlyIfEmpty);
2080*d57664e9SAndroid Build Coastguard Worker return true;
2081*d57664e9SAndroid Build Coastguard Worker }
2082*d57664e9SAndroid Build Coastguard Worker }
2083*d57664e9SAndroid Build Coastguard Worker }
2084*d57664e9SAndroid Build Coastguard Worker return false;
2085*d57664e9SAndroid Build Coastguard Worker }
2086*d57664e9SAndroid Build Coastguard Worker
appendTypeComment(const String16 & package,const String16 & type,const String16 & name,const String16 & comment)2087*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::appendTypeComment(const String16& package,
2088*d57664e9SAndroid Build Coastguard Worker const String16& type,
2089*d57664e9SAndroid Build Coastguard Worker const String16& name,
2090*d57664e9SAndroid Build Coastguard Worker const String16& comment)
2091*d57664e9SAndroid Build Coastguard Worker {
2092*d57664e9SAndroid Build Coastguard Worker if (comment.size() <= 0) {
2093*d57664e9SAndroid Build Coastguard Worker return true;
2094*d57664e9SAndroid Build Coastguard Worker }
2095*d57664e9SAndroid Build Coastguard Worker
2096*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
2097*d57664e9SAndroid Build Coastguard Worker if (p != NULL) {
2098*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
2099*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
2100*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getConfigs().valueFor(name);
2101*d57664e9SAndroid Build Coastguard Worker if (c != NULL) {
2102*d57664e9SAndroid Build Coastguard Worker c->appendTypeComment(comment);
2103*d57664e9SAndroid Build Coastguard Worker return true;
2104*d57664e9SAndroid Build Coastguard Worker }
2105*d57664e9SAndroid Build Coastguard Worker }
2106*d57664e9SAndroid Build Coastguard Worker }
2107*d57664e9SAndroid Build Coastguard Worker return false;
2108*d57664e9SAndroid Build Coastguard Worker }
2109*d57664e9SAndroid Build Coastguard Worker
makeAttribute(const String16 & package,const String16 & name,const SourcePos & source,int32_t format,const String16 & comment,bool shouldAppendComment)2110*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::makeAttribute(const String16& package,
2111*d57664e9SAndroid Build Coastguard Worker const String16& name,
2112*d57664e9SAndroid Build Coastguard Worker const SourcePos& source,
2113*d57664e9SAndroid Build Coastguard Worker int32_t format,
2114*d57664e9SAndroid Build Coastguard Worker const String16& comment,
2115*d57664e9SAndroid Build Coastguard Worker bool shouldAppendComment) {
2116*d57664e9SAndroid Build Coastguard Worker const String16 attr16("attr");
2117*d57664e9SAndroid Build Coastguard Worker
2118*d57664e9SAndroid Build Coastguard Worker // First look for this in the included resources...
2119*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
2120*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
2121*d57664e9SAndroid Build Coastguard Worker attr16.c_str(), attr16.size(),
2122*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size());
2123*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
2124*d57664e9SAndroid Build Coastguard Worker source.error("Attribute \"%s\" has already been defined", String8(name).c_str());
2125*d57664e9SAndroid Build Coastguard Worker return false;
2126*d57664e9SAndroid Build Coastguard Worker }
2127*d57664e9SAndroid Build Coastguard Worker
2128*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::Entry> entry = getEntry(package, attr16, name, source, false);
2129*d57664e9SAndroid Build Coastguard Worker if (entry == NULL) {
2130*d57664e9SAndroid Build Coastguard Worker source.error("Failed to create entry attr/%s", String8(name).c_str());
2131*d57664e9SAndroid Build Coastguard Worker return false;
2132*d57664e9SAndroid Build Coastguard Worker }
2133*d57664e9SAndroid Build Coastguard Worker
2134*d57664e9SAndroid Build Coastguard Worker if (entry->makeItABag(source) != NO_ERROR) {
2135*d57664e9SAndroid Build Coastguard Worker return false;
2136*d57664e9SAndroid Build Coastguard Worker }
2137*d57664e9SAndroid Build Coastguard Worker
2138*d57664e9SAndroid Build Coastguard Worker const String16 formatKey16("^type");
2139*d57664e9SAndroid Build Coastguard Worker const String16 formatValue16(String8::format("%d", format));
2140*d57664e9SAndroid Build Coastguard Worker
2141*d57664e9SAndroid Build Coastguard Worker ssize_t idx = entry->getBag().indexOfKey(formatKey16);
2142*d57664e9SAndroid Build Coastguard Worker if (idx >= 0) {
2143*d57664e9SAndroid Build Coastguard Worker // We have already set a format for this attribute, check if they are different.
2144*d57664e9SAndroid Build Coastguard Worker // We allow duplicate attribute definitions so long as they are identical.
2145*d57664e9SAndroid Build Coastguard Worker // This is to ensure inter-operation with libraries that define the same generic attribute.
2146*d57664e9SAndroid Build Coastguard Worker const Item& formatItem = entry->getBag().valueAt(idx);
2147*d57664e9SAndroid Build Coastguard Worker if ((format & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) ||
2148*d57664e9SAndroid Build Coastguard Worker formatItem.value != formatValue16) {
2149*d57664e9SAndroid Build Coastguard Worker source.error("Attribute \"%s\" already defined with incompatible format.\n"
2150*d57664e9SAndroid Build Coastguard Worker "%s:%d: Original attribute defined here.",
2151*d57664e9SAndroid Build Coastguard Worker String8(name).c_str(), formatItem.sourcePos.file.c_str(),
2152*d57664e9SAndroid Build Coastguard Worker formatItem.sourcePos.line);
2153*d57664e9SAndroid Build Coastguard Worker return false;
2154*d57664e9SAndroid Build Coastguard Worker }
2155*d57664e9SAndroid Build Coastguard Worker } else {
2156*d57664e9SAndroid Build Coastguard Worker entry->addToBag(source, formatKey16, formatValue16);
2157*d57664e9SAndroid Build Coastguard Worker // Increment the number of resources we have. This is used to determine if we should
2158*d57664e9SAndroid Build Coastguard Worker // even generate a resource table.
2159*d57664e9SAndroid Build Coastguard Worker mNumLocal++;
2160*d57664e9SAndroid Build Coastguard Worker }
2161*d57664e9SAndroid Build Coastguard Worker appendComment(package, attr16, name, comment, shouldAppendComment);
2162*d57664e9SAndroid Build Coastguard Worker return true;
2163*d57664e9SAndroid Build Coastguard Worker }
2164*d57664e9SAndroid Build Coastguard Worker
canAddEntry(const SourcePos & pos,const String16 & package,const String16 & type,const String16 & name)2165*d57664e9SAndroid Build Coastguard Worker void ResourceTable::canAddEntry(const SourcePos& pos,
2166*d57664e9SAndroid Build Coastguard Worker const String16& package, const String16& type, const String16& name)
2167*d57664e9SAndroid Build Coastguard Worker {
2168*d57664e9SAndroid Build Coastguard Worker sp<Type> t = getType(package, type, pos);
2169*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
2170*d57664e9SAndroid Build Coastguard Worker t->canAddEntry(name);
2171*d57664e9SAndroid Build Coastguard Worker }
2172*d57664e9SAndroid Build Coastguard Worker }
2173*d57664e9SAndroid Build Coastguard Worker
size() const2174*d57664e9SAndroid Build Coastguard Worker size_t ResourceTable::size() const {
2175*d57664e9SAndroid Build Coastguard Worker return mPackages.size();
2176*d57664e9SAndroid Build Coastguard Worker }
2177*d57664e9SAndroid Build Coastguard Worker
numLocalResources() const2178*d57664e9SAndroid Build Coastguard Worker size_t ResourceTable::numLocalResources() const {
2179*d57664e9SAndroid Build Coastguard Worker return mNumLocal;
2180*d57664e9SAndroid Build Coastguard Worker }
2181*d57664e9SAndroid Build Coastguard Worker
hasResources() const2182*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::hasResources() const {
2183*d57664e9SAndroid Build Coastguard Worker return mNumLocal > 0;
2184*d57664e9SAndroid Build Coastguard Worker }
2185*d57664e9SAndroid Build Coastguard Worker
flatten(Bundle * bundle,const sp<const ResourceFilter> & filter,const bool isBase)2186*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
2187*d57664e9SAndroid Build Coastguard Worker const bool isBase)
2188*d57664e9SAndroid Build Coastguard Worker {
2189*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
2190*d57664e9SAndroid Build Coastguard Worker status_t err = flatten(bundle, filter, data, isBase);
2191*d57664e9SAndroid Build Coastguard Worker return err == NO_ERROR ? data : NULL;
2192*d57664e9SAndroid Build Coastguard Worker }
2193*d57664e9SAndroid Build Coastguard Worker
getResId(const sp<Package> & p,const sp<Type> & t,uint32_t nameId)2194*d57664e9SAndroid Build Coastguard Worker inline uint32_t ResourceTable::getResId(const sp<Package>& p,
2195*d57664e9SAndroid Build Coastguard Worker const sp<Type>& t,
2196*d57664e9SAndroid Build Coastguard Worker uint32_t nameId)
2197*d57664e9SAndroid Build Coastguard Worker {
2198*d57664e9SAndroid Build Coastguard Worker return makeResId(p->getAssignedId(), t->getIndex(), nameId);
2199*d57664e9SAndroid Build Coastguard Worker }
2200*d57664e9SAndroid Build Coastguard Worker
getResId(const String16 & package,const String16 & type,const String16 & name,bool onlyPublic) const2201*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceTable::getResId(const String16& package,
2202*d57664e9SAndroid Build Coastguard Worker const String16& type,
2203*d57664e9SAndroid Build Coastguard Worker const String16& name,
2204*d57664e9SAndroid Build Coastguard Worker bool onlyPublic) const
2205*d57664e9SAndroid Build Coastguard Worker {
2206*d57664e9SAndroid Build Coastguard Worker uint32_t id = ResourceIdCache::lookup(package, type, name, onlyPublic);
2207*d57664e9SAndroid Build Coastguard Worker if (id != 0) return id; // cache hit
2208*d57664e9SAndroid Build Coastguard Worker
2209*d57664e9SAndroid Build Coastguard Worker // First look for this in the included resources...
2210*d57664e9SAndroid Build Coastguard Worker uint32_t specFlags = 0;
2211*d57664e9SAndroid Build Coastguard Worker uint32_t rid = mAssets->getIncludedResources()
2212*d57664e9SAndroid Build Coastguard Worker .identifierForName(name.c_str(), name.size(),
2213*d57664e9SAndroid Build Coastguard Worker type.c_str(), type.size(),
2214*d57664e9SAndroid Build Coastguard Worker package.c_str(), package.size(),
2215*d57664e9SAndroid Build Coastguard Worker &specFlags);
2216*d57664e9SAndroid Build Coastguard Worker if (rid != 0) {
2217*d57664e9SAndroid Build Coastguard Worker if (onlyPublic && (specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
2218*d57664e9SAndroid Build Coastguard Worker // If this is a feature split and the resource has the same
2219*d57664e9SAndroid Build Coastguard Worker // package name as us, then everything is public.
2220*d57664e9SAndroid Build Coastguard Worker if (mPackageType != AppFeature || mAssetsPackage != package) {
2221*d57664e9SAndroid Build Coastguard Worker return 0;
2222*d57664e9SAndroid Build Coastguard Worker }
2223*d57664e9SAndroid Build Coastguard Worker }
2224*d57664e9SAndroid Build Coastguard Worker
2225*d57664e9SAndroid Build Coastguard Worker return ResourceIdCache::store(package, type, name, onlyPublic, rid);
2226*d57664e9SAndroid Build Coastguard Worker }
2227*d57664e9SAndroid Build Coastguard Worker
2228*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
2229*d57664e9SAndroid Build Coastguard Worker if (p == NULL) return 0;
2230*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
2231*d57664e9SAndroid Build Coastguard Worker if (t == NULL) return 0;
2232*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getConfigs().valueFor(name);
2233*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2234*d57664e9SAndroid Build Coastguard Worker if (type != String16("attr")) {
2235*d57664e9SAndroid Build Coastguard Worker return 0;
2236*d57664e9SAndroid Build Coastguard Worker }
2237*d57664e9SAndroid Build Coastguard Worker t = p->getTypes().valueFor(String16(kAttrPrivateType));
2238*d57664e9SAndroid Build Coastguard Worker if (t == NULL) return 0;
2239*d57664e9SAndroid Build Coastguard Worker c = t->getConfigs().valueFor(name);
2240*d57664e9SAndroid Build Coastguard Worker if (c == NULL) return 0;
2241*d57664e9SAndroid Build Coastguard Worker }
2242*d57664e9SAndroid Build Coastguard Worker int32_t ei = c->getEntryIndex();
2243*d57664e9SAndroid Build Coastguard Worker if (ei < 0) return 0;
2244*d57664e9SAndroid Build Coastguard Worker
2245*d57664e9SAndroid Build Coastguard Worker return ResourceIdCache::store(package, type, name, onlyPublic,
2246*d57664e9SAndroid Build Coastguard Worker getResId(p, t, ei));
2247*d57664e9SAndroid Build Coastguard Worker }
2248*d57664e9SAndroid Build Coastguard Worker
getResId(const String16 & ref,const String16 * defType,const String16 * defPackage,const char ** outErrorMsg,bool onlyPublic) const2249*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceTable::getResId(const String16& ref,
2250*d57664e9SAndroid Build Coastguard Worker const String16* defType,
2251*d57664e9SAndroid Build Coastguard Worker const String16* defPackage,
2252*d57664e9SAndroid Build Coastguard Worker const char** outErrorMsg,
2253*d57664e9SAndroid Build Coastguard Worker bool onlyPublic) const
2254*d57664e9SAndroid Build Coastguard Worker {
2255*d57664e9SAndroid Build Coastguard Worker String16 package, type, name;
2256*d57664e9SAndroid Build Coastguard Worker bool refOnlyPublic = true;
2257*d57664e9SAndroid Build Coastguard Worker if (!ResTable::expandResourceRef(
2258*d57664e9SAndroid Build Coastguard Worker ref.c_str(), ref.size(), &package, &type, &name,
2259*d57664e9SAndroid Build Coastguard Worker defType, defPackage ? defPackage:&mAssetsPackage,
2260*d57664e9SAndroid Build Coastguard Worker outErrorMsg, &refOnlyPublic)) {
2261*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
2262*d57664e9SAndroid Build Coastguard Worker printf("Expanding resource: ref=%s\n", String8(ref).c_str());
2263*d57664e9SAndroid Build Coastguard Worker printf("Expanding resource: defType=%s\n",
2264*d57664e9SAndroid Build Coastguard Worker defType ? String8(*defType).c_str() : "NULL");
2265*d57664e9SAndroid Build Coastguard Worker printf("Expanding resource: defPackage=%s\n",
2266*d57664e9SAndroid Build Coastguard Worker defPackage ? String8(*defPackage).c_str() : "NULL");
2267*d57664e9SAndroid Build Coastguard Worker printf("Expanding resource: ref=%s\n", String8(ref).c_str());
2268*d57664e9SAndroid Build Coastguard Worker printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
2269*d57664e9SAndroid Build Coastguard Worker String8(package).c_str(), String8(type).c_str(),
2270*d57664e9SAndroid Build Coastguard Worker String8(name).c_str());
2271*d57664e9SAndroid Build Coastguard Worker }
2272*d57664e9SAndroid Build Coastguard Worker return 0;
2273*d57664e9SAndroid Build Coastguard Worker }
2274*d57664e9SAndroid Build Coastguard Worker uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic);
2275*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
2276*d57664e9SAndroid Build Coastguard Worker printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
2277*d57664e9SAndroid Build Coastguard Worker String8(package).c_str(), String8(type).c_str(),
2278*d57664e9SAndroid Build Coastguard Worker String8(name).c_str(), res);
2279*d57664e9SAndroid Build Coastguard Worker }
2280*d57664e9SAndroid Build Coastguard Worker if (res == 0) {
2281*d57664e9SAndroid Build Coastguard Worker if (outErrorMsg)
2282*d57664e9SAndroid Build Coastguard Worker *outErrorMsg = "No resource found that matches the given name";
2283*d57664e9SAndroid Build Coastguard Worker }
2284*d57664e9SAndroid Build Coastguard Worker return res;
2285*d57664e9SAndroid Build Coastguard Worker }
2286*d57664e9SAndroid Build Coastguard Worker
isValidResourceName(const String16 & s)2287*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::isValidResourceName(const String16& s)
2288*d57664e9SAndroid Build Coastguard Worker {
2289*d57664e9SAndroid Build Coastguard Worker const char16_t* p = s.c_str();
2290*d57664e9SAndroid Build Coastguard Worker bool first = true;
2291*d57664e9SAndroid Build Coastguard Worker while (*p) {
2292*d57664e9SAndroid Build Coastguard Worker if ((*p >= 'a' && *p <= 'z')
2293*d57664e9SAndroid Build Coastguard Worker || (*p >= 'A' && *p <= 'Z')
2294*d57664e9SAndroid Build Coastguard Worker || *p == '_'
2295*d57664e9SAndroid Build Coastguard Worker || (!first && *p >= '0' && *p <= '9')) {
2296*d57664e9SAndroid Build Coastguard Worker first = false;
2297*d57664e9SAndroid Build Coastguard Worker p++;
2298*d57664e9SAndroid Build Coastguard Worker continue;
2299*d57664e9SAndroid Build Coastguard Worker }
2300*d57664e9SAndroid Build Coastguard Worker return false;
2301*d57664e9SAndroid Build Coastguard Worker }
2302*d57664e9SAndroid Build Coastguard Worker return true;
2303*d57664e9SAndroid Build Coastguard Worker }
2304*d57664e9SAndroid Build Coastguard Worker
stringToValue(Res_value * outValue,StringPool * pool,const String16 & str,bool preserveSpaces,bool coerceType,uint32_t attrID,const Vector<StringPool::entry_style_span> * style,String16 * outStr,void * accessorCookie,uint32_t attrType,const String8 * configTypeName,const ConfigDescription * config)2305*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::stringToValue(Res_value* outValue, StringPool* pool,
2306*d57664e9SAndroid Build Coastguard Worker const String16& str,
2307*d57664e9SAndroid Build Coastguard Worker bool preserveSpaces, bool coerceType,
2308*d57664e9SAndroid Build Coastguard Worker uint32_t attrID,
2309*d57664e9SAndroid Build Coastguard Worker const Vector<StringPool::entry_style_span>* style,
2310*d57664e9SAndroid Build Coastguard Worker String16* outStr, void* accessorCookie,
2311*d57664e9SAndroid Build Coastguard Worker uint32_t attrType, const String8* configTypeName,
2312*d57664e9SAndroid Build Coastguard Worker const ConfigDescription* config)
2313*d57664e9SAndroid Build Coastguard Worker {
2314*d57664e9SAndroid Build Coastguard Worker String16 finalStr;
2315*d57664e9SAndroid Build Coastguard Worker
2316*d57664e9SAndroid Build Coastguard Worker bool res = true;
2317*d57664e9SAndroid Build Coastguard Worker if (style == NULL || style->size() == 0) {
2318*d57664e9SAndroid Build Coastguard Worker // Text is not styled so it can be any type... let's figure it out.
2319*d57664e9SAndroid Build Coastguard Worker res = mAssets->getIncludedResources()
2320*d57664e9SAndroid Build Coastguard Worker .stringToValue(outValue, &finalStr, str.c_str(), str.size(), preserveSpaces,
2321*d57664e9SAndroid Build Coastguard Worker coerceType, attrID, NULL, &mAssetsPackage, this,
2322*d57664e9SAndroid Build Coastguard Worker accessorCookie, attrType);
2323*d57664e9SAndroid Build Coastguard Worker } else {
2324*d57664e9SAndroid Build Coastguard Worker // Styled text can only be a string, and while collecting the style
2325*d57664e9SAndroid Build Coastguard Worker // information we have already processed that string!
2326*d57664e9SAndroid Build Coastguard Worker outValue->size = sizeof(Res_value);
2327*d57664e9SAndroid Build Coastguard Worker outValue->res0 = 0;
2328*d57664e9SAndroid Build Coastguard Worker outValue->dataType = outValue->TYPE_STRING;
2329*d57664e9SAndroid Build Coastguard Worker outValue->data = 0;
2330*d57664e9SAndroid Build Coastguard Worker finalStr = str;
2331*d57664e9SAndroid Build Coastguard Worker }
2332*d57664e9SAndroid Build Coastguard Worker
2333*d57664e9SAndroid Build Coastguard Worker if (!res) {
2334*d57664e9SAndroid Build Coastguard Worker return false;
2335*d57664e9SAndroid Build Coastguard Worker }
2336*d57664e9SAndroid Build Coastguard Worker
2337*d57664e9SAndroid Build Coastguard Worker if (outValue->dataType == outValue->TYPE_STRING) {
2338*d57664e9SAndroid Build Coastguard Worker // Should do better merging styles.
2339*d57664e9SAndroid Build Coastguard Worker if (pool) {
2340*d57664e9SAndroid Build Coastguard Worker String8 configStr;
2341*d57664e9SAndroid Build Coastguard Worker if (config != NULL) {
2342*d57664e9SAndroid Build Coastguard Worker configStr = config->toString();
2343*d57664e9SAndroid Build Coastguard Worker } else {
2344*d57664e9SAndroid Build Coastguard Worker configStr = "(null)";
2345*d57664e9SAndroid Build Coastguard Worker }
2346*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
2347*d57664e9SAndroid Build Coastguard Worker printf("Adding to pool string style #%zu config %s: %s\n",
2348*d57664e9SAndroid Build Coastguard Worker style != NULL ? style->size() : 0U,
2349*d57664e9SAndroid Build Coastguard Worker configStr.c_str(), String8(finalStr).c_str());
2350*d57664e9SAndroid Build Coastguard Worker }
2351*d57664e9SAndroid Build Coastguard Worker if (style != NULL && style->size() > 0) {
2352*d57664e9SAndroid Build Coastguard Worker outValue->data = pool->add(finalStr, *style, configTypeName, config);
2353*d57664e9SAndroid Build Coastguard Worker } else {
2354*d57664e9SAndroid Build Coastguard Worker outValue->data = pool->add(finalStr, true, configTypeName, config);
2355*d57664e9SAndroid Build Coastguard Worker }
2356*d57664e9SAndroid Build Coastguard Worker } else {
2357*d57664e9SAndroid Build Coastguard Worker // Caller will fill this in later.
2358*d57664e9SAndroid Build Coastguard Worker outValue->data = 0;
2359*d57664e9SAndroid Build Coastguard Worker }
2360*d57664e9SAndroid Build Coastguard Worker
2361*d57664e9SAndroid Build Coastguard Worker if (outStr) {
2362*d57664e9SAndroid Build Coastguard Worker *outStr = finalStr;
2363*d57664e9SAndroid Build Coastguard Worker }
2364*d57664e9SAndroid Build Coastguard Worker
2365*d57664e9SAndroid Build Coastguard Worker }
2366*d57664e9SAndroid Build Coastguard Worker
2367*d57664e9SAndroid Build Coastguard Worker return true;
2368*d57664e9SAndroid Build Coastguard Worker }
2369*d57664e9SAndroid Build Coastguard Worker
getCustomResource(const String16 & package,const String16 & type,const String16 & name) const2370*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceTable::getCustomResource(
2371*d57664e9SAndroid Build Coastguard Worker const String16& package, const String16& type, const String16& name) const
2372*d57664e9SAndroid Build Coastguard Worker {
2373*d57664e9SAndroid Build Coastguard Worker //printf("getCustomResource: %s %s %s\n", String8(package).c_str(),
2374*d57664e9SAndroid Build Coastguard Worker // String8(type).c_str(), String8(name).c_str());
2375*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mPackages.valueFor(package);
2376*d57664e9SAndroid Build Coastguard Worker if (p == NULL) return 0;
2377*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(type);
2378*d57664e9SAndroid Build Coastguard Worker if (t == NULL) return 0;
2379*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getConfigs().valueFor(name);
2380*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2381*d57664e9SAndroid Build Coastguard Worker if (type != String16("attr")) {
2382*d57664e9SAndroid Build Coastguard Worker return 0;
2383*d57664e9SAndroid Build Coastguard Worker }
2384*d57664e9SAndroid Build Coastguard Worker t = p->getTypes().valueFor(String16(kAttrPrivateType));
2385*d57664e9SAndroid Build Coastguard Worker if (t == NULL) return 0;
2386*d57664e9SAndroid Build Coastguard Worker c = t->getConfigs().valueFor(name);
2387*d57664e9SAndroid Build Coastguard Worker if (c == NULL) return 0;
2388*d57664e9SAndroid Build Coastguard Worker }
2389*d57664e9SAndroid Build Coastguard Worker int32_t ei = c->getEntryIndex();
2390*d57664e9SAndroid Build Coastguard Worker if (ei < 0) return 0;
2391*d57664e9SAndroid Build Coastguard Worker return getResId(p, t, ei);
2392*d57664e9SAndroid Build Coastguard Worker }
2393*d57664e9SAndroid Build Coastguard Worker
getCustomResourceWithCreation(const String16 & package,const String16 & type,const String16 & name,const bool createIfNotFound)2394*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceTable::getCustomResourceWithCreation(
2395*d57664e9SAndroid Build Coastguard Worker const String16& package, const String16& type, const String16& name,
2396*d57664e9SAndroid Build Coastguard Worker const bool createIfNotFound)
2397*d57664e9SAndroid Build Coastguard Worker {
2398*d57664e9SAndroid Build Coastguard Worker uint32_t resId = getCustomResource(package, type, name);
2399*d57664e9SAndroid Build Coastguard Worker if (resId != 0 || !createIfNotFound) {
2400*d57664e9SAndroid Build Coastguard Worker return resId;
2401*d57664e9SAndroid Build Coastguard Worker }
2402*d57664e9SAndroid Build Coastguard Worker
2403*d57664e9SAndroid Build Coastguard Worker if (mAssetsPackage != package) {
2404*d57664e9SAndroid Build Coastguard Worker mCurrentXmlPos.error("creating resource for external package %s: %s/%s.",
2405*d57664e9SAndroid Build Coastguard Worker String8(package).c_str(), String8(type).c_str(), String8(name).c_str());
2406*d57664e9SAndroid Build Coastguard Worker if (package == String16("android")) {
2407*d57664e9SAndroid Build Coastguard Worker mCurrentXmlPos.printf("did you mean to use @+id instead of @+android:id?");
2408*d57664e9SAndroid Build Coastguard Worker }
2409*d57664e9SAndroid Build Coastguard Worker return 0;
2410*d57664e9SAndroid Build Coastguard Worker }
2411*d57664e9SAndroid Build Coastguard Worker
2412*d57664e9SAndroid Build Coastguard Worker String16 value("false");
2413*d57664e9SAndroid Build Coastguard Worker status_t status = addEntry(mCurrentXmlPos, package, type, name, value, NULL, NULL, true);
2414*d57664e9SAndroid Build Coastguard Worker if (status == NO_ERROR) {
2415*d57664e9SAndroid Build Coastguard Worker resId = getResId(package, type, name);
2416*d57664e9SAndroid Build Coastguard Worker return resId;
2417*d57664e9SAndroid Build Coastguard Worker }
2418*d57664e9SAndroid Build Coastguard Worker return 0;
2419*d57664e9SAndroid Build Coastguard Worker }
2420*d57664e9SAndroid Build Coastguard Worker
getRemappedPackage(uint32_t origPackage) const2421*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceTable::getRemappedPackage(uint32_t origPackage) const
2422*d57664e9SAndroid Build Coastguard Worker {
2423*d57664e9SAndroid Build Coastguard Worker return origPackage;
2424*d57664e9SAndroid Build Coastguard Worker }
2425*d57664e9SAndroid Build Coastguard Worker
getAttributeType(uint32_t attrID,uint32_t * outType)2426*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getAttributeType(uint32_t attrID, uint32_t* outType)
2427*d57664e9SAndroid Build Coastguard Worker {
2428*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeType #%08x\n", attrID);
2429*d57664e9SAndroid Build Coastguard Worker Res_value value;
2430*d57664e9SAndroid Build Coastguard Worker if (getItemValue(attrID, ResTable_map::ATTR_TYPE, &value)) {
2431*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeType #%08x (%s): #%08x\n", attrID,
2432*d57664e9SAndroid Build Coastguard Worker // String8(getEntry(attrID)->getName()).c_str(), value.data);
2433*d57664e9SAndroid Build Coastguard Worker *outType = value.data;
2434*d57664e9SAndroid Build Coastguard Worker return true;
2435*d57664e9SAndroid Build Coastguard Worker }
2436*d57664e9SAndroid Build Coastguard Worker return false;
2437*d57664e9SAndroid Build Coastguard Worker }
2438*d57664e9SAndroid Build Coastguard Worker
getAttributeMin(uint32_t attrID,uint32_t * outMin)2439*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getAttributeMin(uint32_t attrID, uint32_t* outMin)
2440*d57664e9SAndroid Build Coastguard Worker {
2441*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeMin #%08x\n", attrID);
2442*d57664e9SAndroid Build Coastguard Worker Res_value value;
2443*d57664e9SAndroid Build Coastguard Worker if (getItemValue(attrID, ResTable_map::ATTR_MIN, &value)) {
2444*d57664e9SAndroid Build Coastguard Worker *outMin = value.data;
2445*d57664e9SAndroid Build Coastguard Worker return true;
2446*d57664e9SAndroid Build Coastguard Worker }
2447*d57664e9SAndroid Build Coastguard Worker return false;
2448*d57664e9SAndroid Build Coastguard Worker }
2449*d57664e9SAndroid Build Coastguard Worker
getAttributeMax(uint32_t attrID,uint32_t * outMax)2450*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getAttributeMax(uint32_t attrID, uint32_t* outMax)
2451*d57664e9SAndroid Build Coastguard Worker {
2452*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeMax #%08x\n", attrID);
2453*d57664e9SAndroid Build Coastguard Worker Res_value value;
2454*d57664e9SAndroid Build Coastguard Worker if (getItemValue(attrID, ResTable_map::ATTR_MAX, &value)) {
2455*d57664e9SAndroid Build Coastguard Worker *outMax = value.data;
2456*d57664e9SAndroid Build Coastguard Worker return true;
2457*d57664e9SAndroid Build Coastguard Worker }
2458*d57664e9SAndroid Build Coastguard Worker return false;
2459*d57664e9SAndroid Build Coastguard Worker }
2460*d57664e9SAndroid Build Coastguard Worker
getAttributeL10N(uint32_t attrID)2461*d57664e9SAndroid Build Coastguard Worker uint32_t ResourceTable::getAttributeL10N(uint32_t attrID)
2462*d57664e9SAndroid Build Coastguard Worker {
2463*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeL10N #%08x\n", attrID);
2464*d57664e9SAndroid Build Coastguard Worker Res_value value;
2465*d57664e9SAndroid Build Coastguard Worker if (getItemValue(attrID, ResTable_map::ATTR_L10N, &value)) {
2466*d57664e9SAndroid Build Coastguard Worker return value.data;
2467*d57664e9SAndroid Build Coastguard Worker }
2468*d57664e9SAndroid Build Coastguard Worker return ResTable_map::L10N_NOT_REQUIRED;
2469*d57664e9SAndroid Build Coastguard Worker }
2470*d57664e9SAndroid Build Coastguard Worker
getLocalizationSetting()2471*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getLocalizationSetting()
2472*d57664e9SAndroid Build Coastguard Worker {
2473*d57664e9SAndroid Build Coastguard Worker return mBundle->getRequireLocalization();
2474*d57664e9SAndroid Build Coastguard Worker }
2475*d57664e9SAndroid Build Coastguard Worker
reportError(void * accessorCookie,const char * fmt,...)2476*d57664e9SAndroid Build Coastguard Worker void ResourceTable::reportError(void* accessorCookie, const char* fmt, ...)
2477*d57664e9SAndroid Build Coastguard Worker {
2478*d57664e9SAndroid Build Coastguard Worker if (accessorCookie != NULL && fmt != NULL) {
2479*d57664e9SAndroid Build Coastguard Worker AccessorCookie* ac = (AccessorCookie*)accessorCookie;
2480*d57664e9SAndroid Build Coastguard Worker char buf[1024];
2481*d57664e9SAndroid Build Coastguard Worker va_list ap;
2482*d57664e9SAndroid Build Coastguard Worker va_start(ap, fmt);
2483*d57664e9SAndroid Build Coastguard Worker vsnprintf(buf, sizeof(buf), fmt, ap);
2484*d57664e9SAndroid Build Coastguard Worker va_end(ap);
2485*d57664e9SAndroid Build Coastguard Worker ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n",
2486*d57664e9SAndroid Build Coastguard Worker buf, ac->attr.c_str(), ac->value.c_str());
2487*d57664e9SAndroid Build Coastguard Worker }
2488*d57664e9SAndroid Build Coastguard Worker }
2489*d57664e9SAndroid Build Coastguard Worker
getAttributeKeys(uint32_t attrID,Vector<String16> * outKeys)2490*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getAttributeKeys(
2491*d57664e9SAndroid Build Coastguard Worker uint32_t attrID, Vector<String16>* outKeys)
2492*d57664e9SAndroid Build Coastguard Worker {
2493*d57664e9SAndroid Build Coastguard Worker sp<const Entry> e = getEntry(attrID);
2494*d57664e9SAndroid Build Coastguard Worker if (e != NULL) {
2495*d57664e9SAndroid Build Coastguard Worker const size_t N = e->getBag().size();
2496*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
2497*d57664e9SAndroid Build Coastguard Worker const String16& key = e->getBag().keyAt(i);
2498*d57664e9SAndroid Build Coastguard Worker if (key.size() > 0 && key.c_str()[0] != '^') {
2499*d57664e9SAndroid Build Coastguard Worker outKeys->add(key);
2500*d57664e9SAndroid Build Coastguard Worker }
2501*d57664e9SAndroid Build Coastguard Worker }
2502*d57664e9SAndroid Build Coastguard Worker return true;
2503*d57664e9SAndroid Build Coastguard Worker }
2504*d57664e9SAndroid Build Coastguard Worker return false;
2505*d57664e9SAndroid Build Coastguard Worker }
2506*d57664e9SAndroid Build Coastguard Worker
getAttributeEnum(uint32_t attrID,const char16_t * name,size_t nameLen,Res_value * outValue)2507*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getAttributeEnum(
2508*d57664e9SAndroid Build Coastguard Worker uint32_t attrID, const char16_t* name, size_t nameLen,
2509*d57664e9SAndroid Build Coastguard Worker Res_value* outValue)
2510*d57664e9SAndroid Build Coastguard Worker {
2511*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).c_str());
2512*d57664e9SAndroid Build Coastguard Worker String16 nameStr(name, nameLen);
2513*d57664e9SAndroid Build Coastguard Worker sp<const Entry> e = getEntry(attrID);
2514*d57664e9SAndroid Build Coastguard Worker if (e != NULL) {
2515*d57664e9SAndroid Build Coastguard Worker const size_t N = e->getBag().size();
2516*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
2517*d57664e9SAndroid Build Coastguard Worker //printf("Comparing %s to %s\n", String8(name, nameLen).c_str(),
2518*d57664e9SAndroid Build Coastguard Worker // String8(e->getBag().keyAt(i)).c_str());
2519*d57664e9SAndroid Build Coastguard Worker if (e->getBag().keyAt(i) == nameStr) {
2520*d57664e9SAndroid Build Coastguard Worker return getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, outValue);
2521*d57664e9SAndroid Build Coastguard Worker }
2522*d57664e9SAndroid Build Coastguard Worker }
2523*d57664e9SAndroid Build Coastguard Worker }
2524*d57664e9SAndroid Build Coastguard Worker return false;
2525*d57664e9SAndroid Build Coastguard Worker }
2526*d57664e9SAndroid Build Coastguard Worker
getAttributeFlags(uint32_t attrID,const char16_t * name,size_t nameLen,Res_value * outValue)2527*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getAttributeFlags(
2528*d57664e9SAndroid Build Coastguard Worker uint32_t attrID, const char16_t* name, size_t nameLen,
2529*d57664e9SAndroid Build Coastguard Worker Res_value* outValue)
2530*d57664e9SAndroid Build Coastguard Worker {
2531*d57664e9SAndroid Build Coastguard Worker outValue->dataType = Res_value::TYPE_INT_HEX;
2532*d57664e9SAndroid Build Coastguard Worker outValue->data = 0;
2533*d57664e9SAndroid Build Coastguard Worker
2534*d57664e9SAndroid Build Coastguard Worker //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).c_str());
2535*d57664e9SAndroid Build Coastguard Worker String16 nameStr(name, nameLen);
2536*d57664e9SAndroid Build Coastguard Worker sp<const Entry> e = getEntry(attrID);
2537*d57664e9SAndroid Build Coastguard Worker if (e != NULL) {
2538*d57664e9SAndroid Build Coastguard Worker const size_t N = e->getBag().size();
2539*d57664e9SAndroid Build Coastguard Worker
2540*d57664e9SAndroid Build Coastguard Worker const char16_t* end = name + nameLen;
2541*d57664e9SAndroid Build Coastguard Worker const char16_t* pos = name;
2542*d57664e9SAndroid Build Coastguard Worker while (pos < end) {
2543*d57664e9SAndroid Build Coastguard Worker const char16_t* start = pos;
2544*d57664e9SAndroid Build Coastguard Worker while (pos < end && *pos != '|') {
2545*d57664e9SAndroid Build Coastguard Worker pos++;
2546*d57664e9SAndroid Build Coastguard Worker }
2547*d57664e9SAndroid Build Coastguard Worker
2548*d57664e9SAndroid Build Coastguard Worker String16 nameStr(start, pos-start);
2549*d57664e9SAndroid Build Coastguard Worker size_t i;
2550*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
2551*d57664e9SAndroid Build Coastguard Worker //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).c_str(),
2552*d57664e9SAndroid Build Coastguard Worker // String8(e->getBag().keyAt(i)).c_str());
2553*d57664e9SAndroid Build Coastguard Worker if (e->getBag().keyAt(i) == nameStr) {
2554*d57664e9SAndroid Build Coastguard Worker Res_value val;
2555*d57664e9SAndroid Build Coastguard Worker bool got = getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, &val);
2556*d57664e9SAndroid Build Coastguard Worker if (!got) {
2557*d57664e9SAndroid Build Coastguard Worker return false;
2558*d57664e9SAndroid Build Coastguard Worker }
2559*d57664e9SAndroid Build Coastguard Worker //printf("Got value: 0x%08x\n", val.data);
2560*d57664e9SAndroid Build Coastguard Worker outValue->data |= val.data;
2561*d57664e9SAndroid Build Coastguard Worker break;
2562*d57664e9SAndroid Build Coastguard Worker }
2563*d57664e9SAndroid Build Coastguard Worker }
2564*d57664e9SAndroid Build Coastguard Worker
2565*d57664e9SAndroid Build Coastguard Worker if (i >= N) {
2566*d57664e9SAndroid Build Coastguard Worker // Didn't find this flag identifier.
2567*d57664e9SAndroid Build Coastguard Worker return false;
2568*d57664e9SAndroid Build Coastguard Worker }
2569*d57664e9SAndroid Build Coastguard Worker pos++;
2570*d57664e9SAndroid Build Coastguard Worker }
2571*d57664e9SAndroid Build Coastguard Worker
2572*d57664e9SAndroid Build Coastguard Worker return true;
2573*d57664e9SAndroid Build Coastguard Worker }
2574*d57664e9SAndroid Build Coastguard Worker return false;
2575*d57664e9SAndroid Build Coastguard Worker }
2576*d57664e9SAndroid Build Coastguard Worker
assignResourceIds()2577*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::assignResourceIds()
2578*d57664e9SAndroid Build Coastguard Worker {
2579*d57664e9SAndroid Build Coastguard Worker const size_t N = mOrderedPackages.size();
2580*d57664e9SAndroid Build Coastguard Worker size_t pi;
2581*d57664e9SAndroid Build Coastguard Worker status_t firstError = NO_ERROR;
2582*d57664e9SAndroid Build Coastguard Worker
2583*d57664e9SAndroid Build Coastguard Worker // First generate all bag attributes and assign indices.
2584*d57664e9SAndroid Build Coastguard Worker for (pi=0; pi<N; pi++) {
2585*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mOrderedPackages.itemAt(pi);
2586*d57664e9SAndroid Build Coastguard Worker if (p == NULL || p->getTypes().size() == 0) {
2587*d57664e9SAndroid Build Coastguard Worker // Empty, skip!
2588*d57664e9SAndroid Build Coastguard Worker continue;
2589*d57664e9SAndroid Build Coastguard Worker }
2590*d57664e9SAndroid Build Coastguard Worker
2591*d57664e9SAndroid Build Coastguard Worker if (mPackageType == System) {
2592*d57664e9SAndroid Build Coastguard Worker p->movePrivateAttrs();
2593*d57664e9SAndroid Build Coastguard Worker }
2594*d57664e9SAndroid Build Coastguard Worker
2595*d57664e9SAndroid Build Coastguard Worker // This has no sense for packages being built as AppFeature (aka with a non-zero offset).
2596*d57664e9SAndroid Build Coastguard Worker status_t err = p->applyPublicTypeOrder();
2597*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR && firstError == NO_ERROR) {
2598*d57664e9SAndroid Build Coastguard Worker firstError = err;
2599*d57664e9SAndroid Build Coastguard Worker }
2600*d57664e9SAndroid Build Coastguard Worker
2601*d57664e9SAndroid Build Coastguard Worker // Generate attributes...
2602*d57664e9SAndroid Build Coastguard Worker const size_t N = p->getOrderedTypes().size();
2603*d57664e9SAndroid Build Coastguard Worker size_t ti;
2604*d57664e9SAndroid Build Coastguard Worker for (ti=0; ti<N; ti++) {
2605*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes().itemAt(ti);
2606*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
2607*d57664e9SAndroid Build Coastguard Worker continue;
2608*d57664e9SAndroid Build Coastguard Worker }
2609*d57664e9SAndroid Build Coastguard Worker const size_t N = t->getOrderedConfigs().size();
2610*d57664e9SAndroid Build Coastguard Worker for (size_t ci=0; ci<N; ci++) {
2611*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2612*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2613*d57664e9SAndroid Build Coastguard Worker continue;
2614*d57664e9SAndroid Build Coastguard Worker }
2615*d57664e9SAndroid Build Coastguard Worker const size_t N = c->getEntries().size();
2616*d57664e9SAndroid Build Coastguard Worker for (size_t ei=0; ei<N; ei++) {
2617*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = c->getEntries().valueAt(ei);
2618*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
2619*d57664e9SAndroid Build Coastguard Worker continue;
2620*d57664e9SAndroid Build Coastguard Worker }
2621*d57664e9SAndroid Build Coastguard Worker status_t err = e->generateAttributes(this, p->getName());
2622*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR && firstError == NO_ERROR) {
2623*d57664e9SAndroid Build Coastguard Worker firstError = err;
2624*d57664e9SAndroid Build Coastguard Worker }
2625*d57664e9SAndroid Build Coastguard Worker }
2626*d57664e9SAndroid Build Coastguard Worker }
2627*d57664e9SAndroid Build Coastguard Worker }
2628*d57664e9SAndroid Build Coastguard Worker
2629*d57664e9SAndroid Build Coastguard Worker uint32_t typeIdOffset = 0;
2630*d57664e9SAndroid Build Coastguard Worker if (mPackageType == AppFeature && p->getName() == mAssetsPackage) {
2631*d57664e9SAndroid Build Coastguard Worker typeIdOffset = mTypeIdOffset;
2632*d57664e9SAndroid Build Coastguard Worker }
2633*d57664e9SAndroid Build Coastguard Worker
2634*d57664e9SAndroid Build Coastguard Worker const SourcePos unknown(String8("????"), 0);
2635*d57664e9SAndroid Build Coastguard Worker sp<Type> attr = p->getType(String16("attr"), unknown);
2636*d57664e9SAndroid Build Coastguard Worker
2637*d57664e9SAndroid Build Coastguard Worker // Force creation of ID if we are building feature splits.
2638*d57664e9SAndroid Build Coastguard Worker // Auto-generated ID resources won't apply the type ID offset correctly unless
2639*d57664e9SAndroid Build Coastguard Worker // the offset is applied here first.
2640*d57664e9SAndroid Build Coastguard Worker // b/30607637
2641*d57664e9SAndroid Build Coastguard Worker if (mPackageType == AppFeature && p->getName() == mAssetsPackage) {
2642*d57664e9SAndroid Build Coastguard Worker sp<Type> id = p->getType(String16("id"), unknown);
2643*d57664e9SAndroid Build Coastguard Worker }
2644*d57664e9SAndroid Build Coastguard Worker
2645*d57664e9SAndroid Build Coastguard Worker // Assign indices...
2646*d57664e9SAndroid Build Coastguard Worker const size_t typeCount = p->getOrderedTypes().size();
2647*d57664e9SAndroid Build Coastguard Worker for (size_t ti = 0; ti < typeCount; ti++) {
2648*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes().itemAt(ti);
2649*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
2650*d57664e9SAndroid Build Coastguard Worker continue;
2651*d57664e9SAndroid Build Coastguard Worker }
2652*d57664e9SAndroid Build Coastguard Worker
2653*d57664e9SAndroid Build Coastguard Worker err = t->applyPublicEntryOrder();
2654*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR && firstError == NO_ERROR) {
2655*d57664e9SAndroid Build Coastguard Worker firstError = err;
2656*d57664e9SAndroid Build Coastguard Worker }
2657*d57664e9SAndroid Build Coastguard Worker
2658*d57664e9SAndroid Build Coastguard Worker const size_t N = t->getOrderedConfigs().size();
2659*d57664e9SAndroid Build Coastguard Worker t->setIndex(ti + 1 + typeIdOffset);
2660*d57664e9SAndroid Build Coastguard Worker
2661*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(ti == 0 && attr != t,
2662*d57664e9SAndroid Build Coastguard Worker "First type is not attr!");
2663*d57664e9SAndroid Build Coastguard Worker
2664*d57664e9SAndroid Build Coastguard Worker for (size_t ei=0; ei<N; ei++) {
2665*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(ei);
2666*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2667*d57664e9SAndroid Build Coastguard Worker continue;
2668*d57664e9SAndroid Build Coastguard Worker }
2669*d57664e9SAndroid Build Coastguard Worker c->setEntryIndex(ei);
2670*d57664e9SAndroid Build Coastguard Worker }
2671*d57664e9SAndroid Build Coastguard Worker }
2672*d57664e9SAndroid Build Coastguard Worker
2673*d57664e9SAndroid Build Coastguard Worker
2674*d57664e9SAndroid Build Coastguard Worker // Assign resource IDs to keys in bags...
2675*d57664e9SAndroid Build Coastguard Worker for (size_t ti = 0; ti < typeCount; ti++) {
2676*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes().itemAt(ti);
2677*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
2678*d57664e9SAndroid Build Coastguard Worker continue;
2679*d57664e9SAndroid Build Coastguard Worker }
2680*d57664e9SAndroid Build Coastguard Worker
2681*d57664e9SAndroid Build Coastguard Worker const size_t N = t->getOrderedConfigs().size();
2682*d57664e9SAndroid Build Coastguard Worker for (size_t ci=0; ci<N; ci++) {
2683*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2684*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2685*d57664e9SAndroid Build Coastguard Worker continue;
2686*d57664e9SAndroid Build Coastguard Worker }
2687*d57664e9SAndroid Build Coastguard Worker //printf("Ordered config #%d: %p\n", ci, c.get());
2688*d57664e9SAndroid Build Coastguard Worker const size_t N = c->getEntries().size();
2689*d57664e9SAndroid Build Coastguard Worker for (size_t ei=0; ei<N; ei++) {
2690*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = c->getEntries().valueAt(ei);
2691*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
2692*d57664e9SAndroid Build Coastguard Worker continue;
2693*d57664e9SAndroid Build Coastguard Worker }
2694*d57664e9SAndroid Build Coastguard Worker status_t err = e->assignResourceIds(this, p->getName());
2695*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR && firstError == NO_ERROR) {
2696*d57664e9SAndroid Build Coastguard Worker firstError = err;
2697*d57664e9SAndroid Build Coastguard Worker }
2698*d57664e9SAndroid Build Coastguard Worker }
2699*d57664e9SAndroid Build Coastguard Worker }
2700*d57664e9SAndroid Build Coastguard Worker }
2701*d57664e9SAndroid Build Coastguard Worker }
2702*d57664e9SAndroid Build Coastguard Worker return firstError;
2703*d57664e9SAndroid Build Coastguard Worker }
2704*d57664e9SAndroid Build Coastguard Worker
addSymbols(const sp<AaptSymbols> & outSymbols,bool skipSymbolsWithoutDefaultLocalization)2705*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols,
2706*d57664e9SAndroid Build Coastguard Worker bool skipSymbolsWithoutDefaultLocalization) {
2707*d57664e9SAndroid Build Coastguard Worker const size_t N = mOrderedPackages.size();
2708*d57664e9SAndroid Build Coastguard Worker const String8 defaultLocale;
2709*d57664e9SAndroid Build Coastguard Worker const String16 stringType("string");
2710*d57664e9SAndroid Build Coastguard Worker size_t pi;
2711*d57664e9SAndroid Build Coastguard Worker
2712*d57664e9SAndroid Build Coastguard Worker for (pi=0; pi<N; pi++) {
2713*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mOrderedPackages.itemAt(pi);
2714*d57664e9SAndroid Build Coastguard Worker if (p->getTypes().size() == 0) {
2715*d57664e9SAndroid Build Coastguard Worker // Empty, skip!
2716*d57664e9SAndroid Build Coastguard Worker continue;
2717*d57664e9SAndroid Build Coastguard Worker }
2718*d57664e9SAndroid Build Coastguard Worker
2719*d57664e9SAndroid Build Coastguard Worker const size_t N = p->getOrderedTypes().size();
2720*d57664e9SAndroid Build Coastguard Worker size_t ti;
2721*d57664e9SAndroid Build Coastguard Worker
2722*d57664e9SAndroid Build Coastguard Worker for (ti=0; ti<N; ti++) {
2723*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes().itemAt(ti);
2724*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
2725*d57664e9SAndroid Build Coastguard Worker continue;
2726*d57664e9SAndroid Build Coastguard Worker }
2727*d57664e9SAndroid Build Coastguard Worker
2728*d57664e9SAndroid Build Coastguard Worker const size_t N = t->getOrderedConfigs().size();
2729*d57664e9SAndroid Build Coastguard Worker sp<AaptSymbols> typeSymbols;
2730*d57664e9SAndroid Build Coastguard Worker if (t->getName() == String16(kAttrPrivateType)) {
2731*d57664e9SAndroid Build Coastguard Worker typeSymbols = outSymbols->addNestedSymbol(String8("attr"), t->getPos());
2732*d57664e9SAndroid Build Coastguard Worker } else {
2733*d57664e9SAndroid Build Coastguard Worker typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
2734*d57664e9SAndroid Build Coastguard Worker }
2735*d57664e9SAndroid Build Coastguard Worker
2736*d57664e9SAndroid Build Coastguard Worker if (typeSymbols == NULL) {
2737*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
2738*d57664e9SAndroid Build Coastguard Worker }
2739*d57664e9SAndroid Build Coastguard Worker
2740*d57664e9SAndroid Build Coastguard Worker for (size_t ci=0; ci<N; ci++) {
2741*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2742*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2743*d57664e9SAndroid Build Coastguard Worker continue;
2744*d57664e9SAndroid Build Coastguard Worker }
2745*d57664e9SAndroid Build Coastguard Worker uint32_t rid = getResId(p, t, ci);
2746*d57664e9SAndroid Build Coastguard Worker if (rid == 0) {
2747*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
2748*d57664e9SAndroid Build Coastguard Worker }
2749*d57664e9SAndroid Build Coastguard Worker if (Res_GETPACKAGE(rid) + 1 == p->getAssignedId()) {
2750*d57664e9SAndroid Build Coastguard Worker
2751*d57664e9SAndroid Build Coastguard Worker if (skipSymbolsWithoutDefaultLocalization &&
2752*d57664e9SAndroid Build Coastguard Worker t->getName() == stringType) {
2753*d57664e9SAndroid Build Coastguard Worker
2754*d57664e9SAndroid Build Coastguard Worker // Don't generate symbols for strings without a default localization.
2755*d57664e9SAndroid Build Coastguard Worker if (mHasDefaultLocalization.find(c->getName())
2756*d57664e9SAndroid Build Coastguard Worker == mHasDefaultLocalization.end()) {
2757*d57664e9SAndroid Build Coastguard Worker // printf("Skip symbol [%08x] %s\n", rid,
2758*d57664e9SAndroid Build Coastguard Worker // String8(c->getName()).c_str());
2759*d57664e9SAndroid Build Coastguard Worker continue;
2760*d57664e9SAndroid Build Coastguard Worker }
2761*d57664e9SAndroid Build Coastguard Worker }
2762*d57664e9SAndroid Build Coastguard Worker
2763*d57664e9SAndroid Build Coastguard Worker typeSymbols->addSymbol(String8(c->getName()), rid, c->getPos());
2764*d57664e9SAndroid Build Coastguard Worker
2765*d57664e9SAndroid Build Coastguard Worker String16 comment(c->getComment());
2766*d57664e9SAndroid Build Coastguard Worker typeSymbols->appendComment(String8(c->getName()), comment, c->getPos());
2767*d57664e9SAndroid Build Coastguard Worker //printf("Type symbol [%08x] %s comment: %s\n", rid,
2768*d57664e9SAndroid Build Coastguard Worker // String8(c->getName()).c_str(), String8(comment).c_str());
2769*d57664e9SAndroid Build Coastguard Worker comment = c->getTypeComment();
2770*d57664e9SAndroid Build Coastguard Worker typeSymbols->appendTypeComment(String8(c->getName()), comment);
2771*d57664e9SAndroid Build Coastguard Worker }
2772*d57664e9SAndroid Build Coastguard Worker }
2773*d57664e9SAndroid Build Coastguard Worker }
2774*d57664e9SAndroid Build Coastguard Worker }
2775*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
2776*d57664e9SAndroid Build Coastguard Worker }
2777*d57664e9SAndroid Build Coastguard Worker
2778*d57664e9SAndroid Build Coastguard Worker
2779*d57664e9SAndroid Build Coastguard Worker void
addLocalization(const String16 & name,const String8 & locale,const SourcePos & src)2780*d57664e9SAndroid Build Coastguard Worker ResourceTable::addLocalization(const String16& name, const String8& locale, const SourcePos& src)
2781*d57664e9SAndroid Build Coastguard Worker {
2782*d57664e9SAndroid Build Coastguard Worker mLocalizations[name][locale] = src;
2783*d57664e9SAndroid Build Coastguard Worker }
2784*d57664e9SAndroid Build Coastguard Worker
2785*d57664e9SAndroid Build Coastguard Worker void
addDefaultLocalization(const String16 & name)2786*d57664e9SAndroid Build Coastguard Worker ResourceTable::addDefaultLocalization(const String16& name)
2787*d57664e9SAndroid Build Coastguard Worker {
2788*d57664e9SAndroid Build Coastguard Worker mHasDefaultLocalization.insert(name);
2789*d57664e9SAndroid Build Coastguard Worker }
2790*d57664e9SAndroid Build Coastguard Worker
2791*d57664e9SAndroid Build Coastguard Worker
2792*d57664e9SAndroid Build Coastguard Worker /*!
2793*d57664e9SAndroid Build Coastguard Worker * Flag various sorts of localization problems. '+' indicates checks already implemented;
2794*d57664e9SAndroid Build Coastguard Worker * '-' indicates checks that will be implemented in the future.
2795*d57664e9SAndroid Build Coastguard Worker *
2796*d57664e9SAndroid Build Coastguard Worker * + A localized string for which no default-locale version exists => warning
2797*d57664e9SAndroid Build Coastguard Worker * + A string for which no version in an explicitly-requested locale exists => warning
2798*d57664e9SAndroid Build Coastguard Worker * + A localized translation of an translateable="false" string => warning
2799*d57664e9SAndroid Build Coastguard Worker * - A localized string not provided in every locale used by the table
2800*d57664e9SAndroid Build Coastguard Worker */
2801*d57664e9SAndroid Build Coastguard Worker status_t
validateLocalizations(void)2802*d57664e9SAndroid Build Coastguard Worker ResourceTable::validateLocalizations(void)
2803*d57664e9SAndroid Build Coastguard Worker {
2804*d57664e9SAndroid Build Coastguard Worker status_t err = NO_ERROR;
2805*d57664e9SAndroid Build Coastguard Worker const String8 defaultLocale;
2806*d57664e9SAndroid Build Coastguard Worker
2807*d57664e9SAndroid Build Coastguard Worker // For all strings...
2808*d57664e9SAndroid Build Coastguard Worker for (const auto& nameIter : mLocalizations) {
2809*d57664e9SAndroid Build Coastguard Worker const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
2810*d57664e9SAndroid Build Coastguard Worker
2811*d57664e9SAndroid Build Coastguard Worker // Look for strings with no default localization
2812*d57664e9SAndroid Build Coastguard Worker if (configSrcMap.count(defaultLocale) == 0) {
2813*d57664e9SAndroid Build Coastguard Worker SourcePos().warning("string '%s' has no default translation.",
2814*d57664e9SAndroid Build Coastguard Worker String8(nameIter.first).c_str());
2815*d57664e9SAndroid Build Coastguard Worker if (mBundle->getVerbose()) {
2816*d57664e9SAndroid Build Coastguard Worker for (const auto& locale : configSrcMap) {
2817*d57664e9SAndroid Build Coastguard Worker locale.second.printf("locale %s found", locale.first.c_str());
2818*d57664e9SAndroid Build Coastguard Worker }
2819*d57664e9SAndroid Build Coastguard Worker }
2820*d57664e9SAndroid Build Coastguard Worker // !!! TODO: throw an error here in some circumstances
2821*d57664e9SAndroid Build Coastguard Worker }
2822*d57664e9SAndroid Build Coastguard Worker
2823*d57664e9SAndroid Build Coastguard Worker // Check that all requested localizations are present for this string
2824*d57664e9SAndroid Build Coastguard Worker if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
2825*d57664e9SAndroid Build Coastguard Worker const char* allConfigs = mBundle->getConfigurations().c_str();
2826*d57664e9SAndroid Build Coastguard Worker const char* start = allConfigs;
2827*d57664e9SAndroid Build Coastguard Worker const char* comma;
2828*d57664e9SAndroid Build Coastguard Worker
2829*d57664e9SAndroid Build Coastguard Worker std::set<String8> missingConfigs;
2830*d57664e9SAndroid Build Coastguard Worker AaptLocaleValue locale;
2831*d57664e9SAndroid Build Coastguard Worker do {
2832*d57664e9SAndroid Build Coastguard Worker String8 config;
2833*d57664e9SAndroid Build Coastguard Worker comma = strchr(start, ',');
2834*d57664e9SAndroid Build Coastguard Worker if (comma != NULL) {
2835*d57664e9SAndroid Build Coastguard Worker config = String8(start, comma - start);
2836*d57664e9SAndroid Build Coastguard Worker start = comma + 1;
2837*d57664e9SAndroid Build Coastguard Worker } else {
2838*d57664e9SAndroid Build Coastguard Worker config = start;
2839*d57664e9SAndroid Build Coastguard Worker }
2840*d57664e9SAndroid Build Coastguard Worker
2841*d57664e9SAndroid Build Coastguard Worker if (!locale.initFromFilterString(config)) {
2842*d57664e9SAndroid Build Coastguard Worker continue;
2843*d57664e9SAndroid Build Coastguard Worker }
2844*d57664e9SAndroid Build Coastguard Worker
2845*d57664e9SAndroid Build Coastguard Worker // don't bother with the pseudolocale "en_XA" or "ar_XB"
2846*d57664e9SAndroid Build Coastguard Worker if (config != "en_XA" && config != "ar_XB") {
2847*d57664e9SAndroid Build Coastguard Worker if (configSrcMap.find(config) == configSrcMap.end()) {
2848*d57664e9SAndroid Build Coastguard Worker // okay, no specific localization found. it's possible that we are
2849*d57664e9SAndroid Build Coastguard Worker // requiring a specific regional localization [e.g. de_DE] but there is an
2850*d57664e9SAndroid Build Coastguard Worker // available string in the generic language localization [e.g. de];
2851*d57664e9SAndroid Build Coastguard Worker // consider that string to have fulfilled the localization requirement.
2852*d57664e9SAndroid Build Coastguard Worker String8 region(config.c_str(), 2);
2853*d57664e9SAndroid Build Coastguard Worker if (configSrcMap.find(region) == configSrcMap.end() &&
2854*d57664e9SAndroid Build Coastguard Worker configSrcMap.count(defaultLocale) == 0) {
2855*d57664e9SAndroid Build Coastguard Worker missingConfigs.insert(config);
2856*d57664e9SAndroid Build Coastguard Worker }
2857*d57664e9SAndroid Build Coastguard Worker }
2858*d57664e9SAndroid Build Coastguard Worker }
2859*d57664e9SAndroid Build Coastguard Worker } while (comma != NULL);
2860*d57664e9SAndroid Build Coastguard Worker
2861*d57664e9SAndroid Build Coastguard Worker if (!missingConfigs.empty()) {
2862*d57664e9SAndroid Build Coastguard Worker String8 configStr;
2863*d57664e9SAndroid Build Coastguard Worker for (const auto& iter : missingConfigs) {
2864*d57664e9SAndroid Build Coastguard Worker configStr.appendFormat(" %s", iter.c_str());
2865*d57664e9SAndroid Build Coastguard Worker }
2866*d57664e9SAndroid Build Coastguard Worker SourcePos().warning("string '%s' is missing %u required localizations:%s",
2867*d57664e9SAndroid Build Coastguard Worker String8(nameIter.first).c_str(),
2868*d57664e9SAndroid Build Coastguard Worker (unsigned int)missingConfigs.size(),
2869*d57664e9SAndroid Build Coastguard Worker configStr.c_str());
2870*d57664e9SAndroid Build Coastguard Worker }
2871*d57664e9SAndroid Build Coastguard Worker }
2872*d57664e9SAndroid Build Coastguard Worker }
2873*d57664e9SAndroid Build Coastguard Worker
2874*d57664e9SAndroid Build Coastguard Worker return err;
2875*d57664e9SAndroid Build Coastguard Worker }
2876*d57664e9SAndroid Build Coastguard Worker
flatten(Bundle * bundle,const sp<const ResourceFilter> & filter,const sp<AaptFile> & dest,const bool isBase)2877*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
2878*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& dest,
2879*d57664e9SAndroid Build Coastguard Worker const bool isBase)
2880*d57664e9SAndroid Build Coastguard Worker {
2881*d57664e9SAndroid Build Coastguard Worker const ConfigDescription nullConfig;
2882*d57664e9SAndroid Build Coastguard Worker
2883*d57664e9SAndroid Build Coastguard Worker const size_t N = mOrderedPackages.size();
2884*d57664e9SAndroid Build Coastguard Worker size_t pi;
2885*d57664e9SAndroid Build Coastguard Worker
2886*d57664e9SAndroid Build Coastguard Worker const static String16 mipmap16("mipmap");
2887*d57664e9SAndroid Build Coastguard Worker
2888*d57664e9SAndroid Build Coastguard Worker bool useUTF8 = !bundle->getUTF16StringsOption();
2889*d57664e9SAndroid Build Coastguard Worker
2890*d57664e9SAndroid Build Coastguard Worker // The libraries this table references.
2891*d57664e9SAndroid Build Coastguard Worker Vector<sp<Package> > libraryPackages;
2892*d57664e9SAndroid Build Coastguard Worker const ResTable& table = mAssets->getIncludedResources();
2893*d57664e9SAndroid Build Coastguard Worker const size_t basePackageCount = table.getBasePackageCount();
2894*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < basePackageCount; i++) {
2895*d57664e9SAndroid Build Coastguard Worker size_t packageId = table.getBasePackageId(i);
2896*d57664e9SAndroid Build Coastguard Worker String16 packageName(table.getBasePackageName(i));
2897*d57664e9SAndroid Build Coastguard Worker if (packageId > 0x01 && packageId != 0x7f &&
2898*d57664e9SAndroid Build Coastguard Worker packageName != String16("android")) {
2899*d57664e9SAndroid Build Coastguard Worker libraryPackages.add(sp<Package>(new Package(packageName, packageId)));
2900*d57664e9SAndroid Build Coastguard Worker }
2901*d57664e9SAndroid Build Coastguard Worker }
2902*d57664e9SAndroid Build Coastguard Worker
2903*d57664e9SAndroid Build Coastguard Worker // Iterate through all data, collecting all values (strings,
2904*d57664e9SAndroid Build Coastguard Worker // references, etc).
2905*d57664e9SAndroid Build Coastguard Worker StringPool valueStrings(useUTF8);
2906*d57664e9SAndroid Build Coastguard Worker Vector<sp<Entry> > allEntries;
2907*d57664e9SAndroid Build Coastguard Worker for (pi=0; pi<N; pi++) {
2908*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mOrderedPackages.itemAt(pi);
2909*d57664e9SAndroid Build Coastguard Worker if (p->getTypes().size() == 0) {
2910*d57664e9SAndroid Build Coastguard Worker continue;
2911*d57664e9SAndroid Build Coastguard Worker }
2912*d57664e9SAndroid Build Coastguard Worker
2913*d57664e9SAndroid Build Coastguard Worker StringPool typeStrings(useUTF8);
2914*d57664e9SAndroid Build Coastguard Worker StringPool keyStrings(useUTF8);
2915*d57664e9SAndroid Build Coastguard Worker
2916*d57664e9SAndroid Build Coastguard Worker ssize_t stringsAdded = 0;
2917*d57664e9SAndroid Build Coastguard Worker const size_t N = p->getOrderedTypes().size();
2918*d57664e9SAndroid Build Coastguard Worker for (size_t ti=0; ti<N; ti++) {
2919*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes().itemAt(ti);
2920*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
2921*d57664e9SAndroid Build Coastguard Worker typeStrings.add(String16("<empty>"), false);
2922*d57664e9SAndroid Build Coastguard Worker stringsAdded++;
2923*d57664e9SAndroid Build Coastguard Worker continue;
2924*d57664e9SAndroid Build Coastguard Worker }
2925*d57664e9SAndroid Build Coastguard Worker
2926*d57664e9SAndroid Build Coastguard Worker while (stringsAdded < t->getIndex() - 1) {
2927*d57664e9SAndroid Build Coastguard Worker typeStrings.add(String16("<empty>"), false);
2928*d57664e9SAndroid Build Coastguard Worker stringsAdded++;
2929*d57664e9SAndroid Build Coastguard Worker }
2930*d57664e9SAndroid Build Coastguard Worker
2931*d57664e9SAndroid Build Coastguard Worker const String16 typeName(t->getName());
2932*d57664e9SAndroid Build Coastguard Worker typeStrings.add(typeName, false);
2933*d57664e9SAndroid Build Coastguard Worker stringsAdded++;
2934*d57664e9SAndroid Build Coastguard Worker
2935*d57664e9SAndroid Build Coastguard Worker // This is a hack to tweak the sorting order of the final strings,
2936*d57664e9SAndroid Build Coastguard Worker // to put stuff that is generally not language-specific first.
2937*d57664e9SAndroid Build Coastguard Worker String8 configTypeName(typeName);
2938*d57664e9SAndroid Build Coastguard Worker if (configTypeName == "drawable" || configTypeName == "layout"
2939*d57664e9SAndroid Build Coastguard Worker || configTypeName == "color" || configTypeName == "anim"
2940*d57664e9SAndroid Build Coastguard Worker || configTypeName == "interpolator" || configTypeName == "animator"
2941*d57664e9SAndroid Build Coastguard Worker || configTypeName == "xml" || configTypeName == "menu"
2942*d57664e9SAndroid Build Coastguard Worker || configTypeName == "mipmap" || configTypeName == "raw") {
2943*d57664e9SAndroid Build Coastguard Worker configTypeName = "1complex";
2944*d57664e9SAndroid Build Coastguard Worker } else {
2945*d57664e9SAndroid Build Coastguard Worker configTypeName = "2value";
2946*d57664e9SAndroid Build Coastguard Worker }
2947*d57664e9SAndroid Build Coastguard Worker
2948*d57664e9SAndroid Build Coastguard Worker // mipmaps don't get filtered, so they will
2949*d57664e9SAndroid Build Coastguard Worker // allways end up in the base. Make sure they
2950*d57664e9SAndroid Build Coastguard Worker // don't end up in a split.
2951*d57664e9SAndroid Build Coastguard Worker if (typeName == mipmap16 && !isBase) {
2952*d57664e9SAndroid Build Coastguard Worker continue;
2953*d57664e9SAndroid Build Coastguard Worker }
2954*d57664e9SAndroid Build Coastguard Worker
2955*d57664e9SAndroid Build Coastguard Worker const bool filterable = (typeName != mipmap16);
2956*d57664e9SAndroid Build Coastguard Worker
2957*d57664e9SAndroid Build Coastguard Worker const size_t N = t->getOrderedConfigs().size();
2958*d57664e9SAndroid Build Coastguard Worker for (size_t ci=0; ci<N; ci++) {
2959*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
2960*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
2961*d57664e9SAndroid Build Coastguard Worker continue;
2962*d57664e9SAndroid Build Coastguard Worker }
2963*d57664e9SAndroid Build Coastguard Worker const size_t N = c->getEntries().size();
2964*d57664e9SAndroid Build Coastguard Worker for (size_t ei=0; ei<N; ei++) {
2965*d57664e9SAndroid Build Coastguard Worker ConfigDescription config = c->getEntries().keyAt(ei);
2966*d57664e9SAndroid Build Coastguard Worker if (filterable && !filter->match(config)) {
2967*d57664e9SAndroid Build Coastguard Worker continue;
2968*d57664e9SAndroid Build Coastguard Worker }
2969*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = c->getEntries().valueAt(ei);
2970*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
2971*d57664e9SAndroid Build Coastguard Worker continue;
2972*d57664e9SAndroid Build Coastguard Worker }
2973*d57664e9SAndroid Build Coastguard Worker e->setNameIndex(keyStrings.add(e->getName(), true));
2974*d57664e9SAndroid Build Coastguard Worker
2975*d57664e9SAndroid Build Coastguard Worker status_t err = e->prepareFlatten(&valueStrings, this,
2976*d57664e9SAndroid Build Coastguard Worker &configTypeName, &config);
2977*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
2978*d57664e9SAndroid Build Coastguard Worker return err;
2979*d57664e9SAndroid Build Coastguard Worker }
2980*d57664e9SAndroid Build Coastguard Worker allEntries.add(e);
2981*d57664e9SAndroid Build Coastguard Worker }
2982*d57664e9SAndroid Build Coastguard Worker }
2983*d57664e9SAndroid Build Coastguard Worker }
2984*d57664e9SAndroid Build Coastguard Worker
2985*d57664e9SAndroid Build Coastguard Worker p->setTypeStrings(typeStrings.createStringBlock());
2986*d57664e9SAndroid Build Coastguard Worker p->setKeyStrings(keyStrings.createStringBlock());
2987*d57664e9SAndroid Build Coastguard Worker }
2988*d57664e9SAndroid Build Coastguard Worker
2989*d57664e9SAndroid Build Coastguard Worker if (bundle->getOutputAPKFile() != NULL) {
2990*d57664e9SAndroid Build Coastguard Worker // Now we want to sort the value strings for better locality. This will
2991*d57664e9SAndroid Build Coastguard Worker // cause the positions of the strings to change, so we need to go back
2992*d57664e9SAndroid Build Coastguard Worker // through out resource entries and update them accordingly. Only need
2993*d57664e9SAndroid Build Coastguard Worker // to do this if actually writing the output file.
2994*d57664e9SAndroid Build Coastguard Worker valueStrings.sortByConfig();
2995*d57664e9SAndroid Build Coastguard Worker for (pi=0; pi<allEntries.size(); pi++) {
2996*d57664e9SAndroid Build Coastguard Worker allEntries[pi]->remapStringValue(&valueStrings);
2997*d57664e9SAndroid Build Coastguard Worker }
2998*d57664e9SAndroid Build Coastguard Worker }
2999*d57664e9SAndroid Build Coastguard Worker
3000*d57664e9SAndroid Build Coastguard Worker ssize_t strAmt = 0;
3001*d57664e9SAndroid Build Coastguard Worker
3002*d57664e9SAndroid Build Coastguard Worker // Now build the array of package chunks.
3003*d57664e9SAndroid Build Coastguard Worker Vector<sp<AaptFile> > flatPackages;
3004*d57664e9SAndroid Build Coastguard Worker for (pi=0; pi<N; pi++) {
3005*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mOrderedPackages.itemAt(pi);
3006*d57664e9SAndroid Build Coastguard Worker if (p->getTypes().size() == 0) {
3007*d57664e9SAndroid Build Coastguard Worker // Empty, skip!
3008*d57664e9SAndroid Build Coastguard Worker continue;
3009*d57664e9SAndroid Build Coastguard Worker }
3010*d57664e9SAndroid Build Coastguard Worker
3011*d57664e9SAndroid Build Coastguard Worker const size_t N = p->getTypeStrings().size();
3012*d57664e9SAndroid Build Coastguard Worker
3013*d57664e9SAndroid Build Coastguard Worker const size_t baseSize = sizeof(ResTable_package);
3014*d57664e9SAndroid Build Coastguard Worker
3015*d57664e9SAndroid Build Coastguard Worker // Start the package data.
3016*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
3017*d57664e9SAndroid Build Coastguard Worker ResTable_package* header = (ResTable_package*)data->editData(baseSize);
3018*d57664e9SAndroid Build Coastguard Worker if (header == NULL) {
3019*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating ResTable_package\n");
3020*d57664e9SAndroid Build Coastguard Worker return NO_MEMORY;
3021*d57664e9SAndroid Build Coastguard Worker }
3022*d57664e9SAndroid Build Coastguard Worker memset(header, 0, sizeof(*header));
3023*d57664e9SAndroid Build Coastguard Worker header->header.type = htods(RES_TABLE_PACKAGE_TYPE);
3024*d57664e9SAndroid Build Coastguard Worker header->header.headerSize = htods(sizeof(*header));
3025*d57664e9SAndroid Build Coastguard Worker header->id = htodl(static_cast<uint32_t>(p->getAssignedId()));
3026*d57664e9SAndroid Build Coastguard Worker strcpy16_htod(header->name, p->getName().c_str());
3027*d57664e9SAndroid Build Coastguard Worker
3028*d57664e9SAndroid Build Coastguard Worker // Write the string blocks.
3029*d57664e9SAndroid Build Coastguard Worker const size_t typeStringsStart = data->getSize();
3030*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> strFile = p->getTypeStringsData();
3031*d57664e9SAndroid Build Coastguard Worker ssize_t amt = data->writeData(strFile->getData(), strFile->getSize());
3032*d57664e9SAndroid Build Coastguard Worker if (kPrintStringMetrics) {
3033*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "**** type strings: %zd\n", amt);
3034*d57664e9SAndroid Build Coastguard Worker }
3035*d57664e9SAndroid Build Coastguard Worker strAmt += amt;
3036*d57664e9SAndroid Build Coastguard Worker if (amt < 0) {
3037*d57664e9SAndroid Build Coastguard Worker return amt;
3038*d57664e9SAndroid Build Coastguard Worker }
3039*d57664e9SAndroid Build Coastguard Worker const size_t keyStringsStart = data->getSize();
3040*d57664e9SAndroid Build Coastguard Worker strFile = p->getKeyStringsData();
3041*d57664e9SAndroid Build Coastguard Worker amt = data->writeData(strFile->getData(), strFile->getSize());
3042*d57664e9SAndroid Build Coastguard Worker if (kPrintStringMetrics) {
3043*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "**** key strings: %zd\n", amt);
3044*d57664e9SAndroid Build Coastguard Worker }
3045*d57664e9SAndroid Build Coastguard Worker strAmt += amt;
3046*d57664e9SAndroid Build Coastguard Worker if (amt < 0) {
3047*d57664e9SAndroid Build Coastguard Worker return amt;
3048*d57664e9SAndroid Build Coastguard Worker }
3049*d57664e9SAndroid Build Coastguard Worker
3050*d57664e9SAndroid Build Coastguard Worker if (isBase) {
3051*d57664e9SAndroid Build Coastguard Worker status_t err = flattenLibraryTable(data, libraryPackages);
3052*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3053*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: failed to write library table\n");
3054*d57664e9SAndroid Build Coastguard Worker return err;
3055*d57664e9SAndroid Build Coastguard Worker }
3056*d57664e9SAndroid Build Coastguard Worker }
3057*d57664e9SAndroid Build Coastguard Worker
3058*d57664e9SAndroid Build Coastguard Worker // Build the type chunks inside of this package.
3059*d57664e9SAndroid Build Coastguard Worker for (size_t ti=0; ti<N; ti++) {
3060*d57664e9SAndroid Build Coastguard Worker // Retrieve them in the same order as the type string block.
3061*d57664e9SAndroid Build Coastguard Worker size_t len;
3062*d57664e9SAndroid Build Coastguard Worker String16 typeName(UnpackOptionalString(p->getTypeStrings().stringAt(ti), &len));
3063*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getTypes().valueFor(typeName);
3064*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"),
3065*d57664e9SAndroid Build Coastguard Worker "Type name %s not found",
3066*d57664e9SAndroid Build Coastguard Worker String8(typeName).c_str());
3067*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
3068*d57664e9SAndroid Build Coastguard Worker continue;
3069*d57664e9SAndroid Build Coastguard Worker }
3070*d57664e9SAndroid Build Coastguard Worker const bool filterable = (typeName != mipmap16);
3071*d57664e9SAndroid Build Coastguard Worker const bool skipEntireType = (typeName == mipmap16 && !isBase);
3072*d57664e9SAndroid Build Coastguard Worker
3073*d57664e9SAndroid Build Coastguard Worker const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
3074*d57664e9SAndroid Build Coastguard Worker
3075*d57664e9SAndroid Build Coastguard Worker // Until a non-NO_ENTRY value has been written for a resource,
3076*d57664e9SAndroid Build Coastguard Worker // that resource is invalid; validResources[i] represents
3077*d57664e9SAndroid Build Coastguard Worker // the item at t->getOrderedConfigs().itemAt(i).
3078*d57664e9SAndroid Build Coastguard Worker Vector<bool> validResources;
3079*d57664e9SAndroid Build Coastguard Worker validResources.insertAt(false, 0, N);
3080*d57664e9SAndroid Build Coastguard Worker
3081*d57664e9SAndroid Build Coastguard Worker // First write the typeSpec chunk, containing information about
3082*d57664e9SAndroid Build Coastguard Worker // each resource entry in this type.
3083*d57664e9SAndroid Build Coastguard Worker {
3084*d57664e9SAndroid Build Coastguard Worker const size_t typeSpecSize = sizeof(ResTable_typeSpec) + sizeof(uint32_t)*N;
3085*d57664e9SAndroid Build Coastguard Worker const size_t typeSpecStart = data->getSize();
3086*d57664e9SAndroid Build Coastguard Worker ResTable_typeSpec* tsHeader = (ResTable_typeSpec*)
3087*d57664e9SAndroid Build Coastguard Worker (((uint8_t*)data->editData(typeSpecStart+typeSpecSize)) + typeSpecStart);
3088*d57664e9SAndroid Build Coastguard Worker if (tsHeader == NULL) {
3089*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating ResTable_typeSpec\n");
3090*d57664e9SAndroid Build Coastguard Worker return NO_MEMORY;
3091*d57664e9SAndroid Build Coastguard Worker }
3092*d57664e9SAndroid Build Coastguard Worker memset(tsHeader, 0, sizeof(*tsHeader));
3093*d57664e9SAndroid Build Coastguard Worker tsHeader->header.type = htods(RES_TABLE_TYPE_SPEC_TYPE);
3094*d57664e9SAndroid Build Coastguard Worker tsHeader->header.headerSize = htods(sizeof(*tsHeader));
3095*d57664e9SAndroid Build Coastguard Worker tsHeader->header.size = htodl(typeSpecSize);
3096*d57664e9SAndroid Build Coastguard Worker tsHeader->id = ti+1;
3097*d57664e9SAndroid Build Coastguard Worker tsHeader->entryCount = htodl(N);
3098*d57664e9SAndroid Build Coastguard Worker
3099*d57664e9SAndroid Build Coastguard Worker uint32_t* typeSpecFlags = (uint32_t*)
3100*d57664e9SAndroid Build Coastguard Worker (((uint8_t*)data->editData())
3101*d57664e9SAndroid Build Coastguard Worker + typeSpecStart + sizeof(ResTable_typeSpec));
3102*d57664e9SAndroid Build Coastguard Worker memset(typeSpecFlags, 0, sizeof(uint32_t)*N);
3103*d57664e9SAndroid Build Coastguard Worker
3104*d57664e9SAndroid Build Coastguard Worker for (size_t ei=0; ei<N; ei++) {
3105*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
3106*d57664e9SAndroid Build Coastguard Worker if (cl == NULL) {
3107*d57664e9SAndroid Build Coastguard Worker continue;
3108*d57664e9SAndroid Build Coastguard Worker }
3109*d57664e9SAndroid Build Coastguard Worker
3110*d57664e9SAndroid Build Coastguard Worker if (cl->getPublic()) {
3111*d57664e9SAndroid Build Coastguard Worker typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
3112*d57664e9SAndroid Build Coastguard Worker }
3113*d57664e9SAndroid Build Coastguard Worker
3114*d57664e9SAndroid Build Coastguard Worker if (skipEntireType) {
3115*d57664e9SAndroid Build Coastguard Worker continue;
3116*d57664e9SAndroid Build Coastguard Worker }
3117*d57664e9SAndroid Build Coastguard Worker
3118*d57664e9SAndroid Build Coastguard Worker const size_t CN = cl->getEntries().size();
3119*d57664e9SAndroid Build Coastguard Worker for (size_t ci=0; ci<CN; ci++) {
3120*d57664e9SAndroid Build Coastguard Worker if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
3121*d57664e9SAndroid Build Coastguard Worker continue;
3122*d57664e9SAndroid Build Coastguard Worker }
3123*d57664e9SAndroid Build Coastguard Worker for (size_t cj=ci+1; cj<CN; cj++) {
3124*d57664e9SAndroid Build Coastguard Worker if (filterable && !filter->match(cl->getEntries().keyAt(cj))) {
3125*d57664e9SAndroid Build Coastguard Worker continue;
3126*d57664e9SAndroid Build Coastguard Worker }
3127*d57664e9SAndroid Build Coastguard Worker typeSpecFlags[ei] |= htodl(
3128*d57664e9SAndroid Build Coastguard Worker cl->getEntries().keyAt(ci).diff(cl->getEntries().keyAt(cj)));
3129*d57664e9SAndroid Build Coastguard Worker }
3130*d57664e9SAndroid Build Coastguard Worker }
3131*d57664e9SAndroid Build Coastguard Worker }
3132*d57664e9SAndroid Build Coastguard Worker }
3133*d57664e9SAndroid Build Coastguard Worker
3134*d57664e9SAndroid Build Coastguard Worker if (skipEntireType) {
3135*d57664e9SAndroid Build Coastguard Worker continue;
3136*d57664e9SAndroid Build Coastguard Worker }
3137*d57664e9SAndroid Build Coastguard Worker
3138*d57664e9SAndroid Build Coastguard Worker // We need to write one type chunk for each configuration for
3139*d57664e9SAndroid Build Coastguard Worker // which we have entries in this type.
3140*d57664e9SAndroid Build Coastguard Worker SortedVector<ConfigDescription> uniqueConfigs;
3141*d57664e9SAndroid Build Coastguard Worker if (t != NULL) {
3142*d57664e9SAndroid Build Coastguard Worker uniqueConfigs = t->getUniqueConfigs();
3143*d57664e9SAndroid Build Coastguard Worker }
3144*d57664e9SAndroid Build Coastguard Worker
3145*d57664e9SAndroid Build Coastguard Worker const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N;
3146*d57664e9SAndroid Build Coastguard Worker
3147*d57664e9SAndroid Build Coastguard Worker const size_t NC = uniqueConfigs.size();
3148*d57664e9SAndroid Build Coastguard Worker for (size_t ci=0; ci<NC; ci++) {
3149*d57664e9SAndroid Build Coastguard Worker const ConfigDescription& config = uniqueConfigs[ci];
3150*d57664e9SAndroid Build Coastguard Worker
3151*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
3152*d57664e9SAndroid Build Coastguard Worker printf("Writing config %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
3153*d57664e9SAndroid Build Coastguard Worker "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
3154*d57664e9SAndroid Build Coastguard Worker "sw%ddp w%ddp h%ddp layout:%d\n",
3155*d57664e9SAndroid Build Coastguard Worker ti + 1,
3156*d57664e9SAndroid Build Coastguard Worker config.mcc, config.mnc,
3157*d57664e9SAndroid Build Coastguard Worker config.language[0] ? config.language[0] : '-',
3158*d57664e9SAndroid Build Coastguard Worker config.language[1] ? config.language[1] : '-',
3159*d57664e9SAndroid Build Coastguard Worker config.country[0] ? config.country[0] : '-',
3160*d57664e9SAndroid Build Coastguard Worker config.country[1] ? config.country[1] : '-',
3161*d57664e9SAndroid Build Coastguard Worker config.orientation,
3162*d57664e9SAndroid Build Coastguard Worker config.uiMode,
3163*d57664e9SAndroid Build Coastguard Worker config.touchscreen,
3164*d57664e9SAndroid Build Coastguard Worker config.density,
3165*d57664e9SAndroid Build Coastguard Worker config.keyboard,
3166*d57664e9SAndroid Build Coastguard Worker config.inputFlags,
3167*d57664e9SAndroid Build Coastguard Worker config.navigation,
3168*d57664e9SAndroid Build Coastguard Worker config.screenWidth,
3169*d57664e9SAndroid Build Coastguard Worker config.screenHeight,
3170*d57664e9SAndroid Build Coastguard Worker config.smallestScreenWidthDp,
3171*d57664e9SAndroid Build Coastguard Worker config.screenWidthDp,
3172*d57664e9SAndroid Build Coastguard Worker config.screenHeightDp,
3173*d57664e9SAndroid Build Coastguard Worker config.screenLayout);
3174*d57664e9SAndroid Build Coastguard Worker }
3175*d57664e9SAndroid Build Coastguard Worker
3176*d57664e9SAndroid Build Coastguard Worker if (filterable && !filter->match(config)) {
3177*d57664e9SAndroid Build Coastguard Worker continue;
3178*d57664e9SAndroid Build Coastguard Worker }
3179*d57664e9SAndroid Build Coastguard Worker
3180*d57664e9SAndroid Build Coastguard Worker const size_t typeStart = data->getSize();
3181*d57664e9SAndroid Build Coastguard Worker
3182*d57664e9SAndroid Build Coastguard Worker ResTable_type* tHeader = (ResTable_type*)
3183*d57664e9SAndroid Build Coastguard Worker (((uint8_t*)data->editData(typeStart+typeSize)) + typeStart);
3184*d57664e9SAndroid Build Coastguard Worker if (tHeader == NULL) {
3185*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating ResTable_type\n");
3186*d57664e9SAndroid Build Coastguard Worker return NO_MEMORY;
3187*d57664e9SAndroid Build Coastguard Worker }
3188*d57664e9SAndroid Build Coastguard Worker
3189*d57664e9SAndroid Build Coastguard Worker memset(tHeader, 0, sizeof(*tHeader));
3190*d57664e9SAndroid Build Coastguard Worker tHeader->header.type = htods(RES_TABLE_TYPE_TYPE);
3191*d57664e9SAndroid Build Coastguard Worker tHeader->header.headerSize = htods(sizeof(*tHeader));
3192*d57664e9SAndroid Build Coastguard Worker tHeader->id = ti+1;
3193*d57664e9SAndroid Build Coastguard Worker tHeader->entryCount = htodl(N);
3194*d57664e9SAndroid Build Coastguard Worker tHeader->entriesStart = htodl(typeSize);
3195*d57664e9SAndroid Build Coastguard Worker tHeader->config = config;
3196*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
3197*d57664e9SAndroid Build Coastguard Worker printf("Writing type %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
3198*d57664e9SAndroid Build Coastguard Worker "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
3199*d57664e9SAndroid Build Coastguard Worker "sw%ddp w%ddp h%ddp layout:%d\n",
3200*d57664e9SAndroid Build Coastguard Worker ti + 1,
3201*d57664e9SAndroid Build Coastguard Worker tHeader->config.mcc, tHeader->config.mnc,
3202*d57664e9SAndroid Build Coastguard Worker tHeader->config.language[0] ? tHeader->config.language[0] : '-',
3203*d57664e9SAndroid Build Coastguard Worker tHeader->config.language[1] ? tHeader->config.language[1] : '-',
3204*d57664e9SAndroid Build Coastguard Worker tHeader->config.country[0] ? tHeader->config.country[0] : '-',
3205*d57664e9SAndroid Build Coastguard Worker tHeader->config.country[1] ? tHeader->config.country[1] : '-',
3206*d57664e9SAndroid Build Coastguard Worker tHeader->config.orientation,
3207*d57664e9SAndroid Build Coastguard Worker tHeader->config.uiMode,
3208*d57664e9SAndroid Build Coastguard Worker tHeader->config.touchscreen,
3209*d57664e9SAndroid Build Coastguard Worker tHeader->config.density,
3210*d57664e9SAndroid Build Coastguard Worker tHeader->config.keyboard,
3211*d57664e9SAndroid Build Coastguard Worker tHeader->config.inputFlags,
3212*d57664e9SAndroid Build Coastguard Worker tHeader->config.navigation,
3213*d57664e9SAndroid Build Coastguard Worker tHeader->config.screenWidth,
3214*d57664e9SAndroid Build Coastguard Worker tHeader->config.screenHeight,
3215*d57664e9SAndroid Build Coastguard Worker tHeader->config.smallestScreenWidthDp,
3216*d57664e9SAndroid Build Coastguard Worker tHeader->config.screenWidthDp,
3217*d57664e9SAndroid Build Coastguard Worker tHeader->config.screenHeightDp,
3218*d57664e9SAndroid Build Coastguard Worker tHeader->config.screenLayout);
3219*d57664e9SAndroid Build Coastguard Worker }
3220*d57664e9SAndroid Build Coastguard Worker tHeader->config.swapHtoD();
3221*d57664e9SAndroid Build Coastguard Worker
3222*d57664e9SAndroid Build Coastguard Worker // Build the entries inside of this type.
3223*d57664e9SAndroid Build Coastguard Worker for (size_t ei=0; ei<N; ei++) {
3224*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> cl = t->getOrderedConfigs().itemAt(ei);
3225*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = NULL;
3226*d57664e9SAndroid Build Coastguard Worker if (cl != NULL) {
3227*d57664e9SAndroid Build Coastguard Worker e = cl->getEntries().valueFor(config);
3228*d57664e9SAndroid Build Coastguard Worker }
3229*d57664e9SAndroid Build Coastguard Worker
3230*d57664e9SAndroid Build Coastguard Worker // Set the offset for this entry in its type.
3231*d57664e9SAndroid Build Coastguard Worker uint32_t* index = (uint32_t*)
3232*d57664e9SAndroid Build Coastguard Worker (((uint8_t*)data->editData())
3233*d57664e9SAndroid Build Coastguard Worker + typeStart + sizeof(ResTable_type));
3234*d57664e9SAndroid Build Coastguard Worker if (e != NULL) {
3235*d57664e9SAndroid Build Coastguard Worker index[ei] = htodl(data->getSize()-typeStart-typeSize);
3236*d57664e9SAndroid Build Coastguard Worker
3237*d57664e9SAndroid Build Coastguard Worker // Create the entry.
3238*d57664e9SAndroid Build Coastguard Worker ssize_t amt = e->flatten(bundle, data, cl->getPublic());
3239*d57664e9SAndroid Build Coastguard Worker if (amt < 0) {
3240*d57664e9SAndroid Build Coastguard Worker return amt;
3241*d57664e9SAndroid Build Coastguard Worker }
3242*d57664e9SAndroid Build Coastguard Worker validResources.editItemAt(ei) = true;
3243*d57664e9SAndroid Build Coastguard Worker } else {
3244*d57664e9SAndroid Build Coastguard Worker index[ei] = htodl(ResTable_type::NO_ENTRY);
3245*d57664e9SAndroid Build Coastguard Worker }
3246*d57664e9SAndroid Build Coastguard Worker }
3247*d57664e9SAndroid Build Coastguard Worker
3248*d57664e9SAndroid Build Coastguard Worker // Fill in the rest of the type information.
3249*d57664e9SAndroid Build Coastguard Worker tHeader = (ResTable_type*)
3250*d57664e9SAndroid Build Coastguard Worker (((uint8_t*)data->editData()) + typeStart);
3251*d57664e9SAndroid Build Coastguard Worker tHeader->header.size = htodl(data->getSize()-typeStart);
3252*d57664e9SAndroid Build Coastguard Worker }
3253*d57664e9SAndroid Build Coastguard Worker
3254*d57664e9SAndroid Build Coastguard Worker // If we're building splits, then each invocation of the flattening
3255*d57664e9SAndroid Build Coastguard Worker // step will have 'missing' entries. Don't warn/error for this case.
3256*d57664e9SAndroid Build Coastguard Worker if (bundle->getSplitConfigurations().empty()) {
3257*d57664e9SAndroid Build Coastguard Worker bool missing_entry = false;
3258*d57664e9SAndroid Build Coastguard Worker const char* log_prefix = bundle->getErrorOnMissingConfigEntry() ?
3259*d57664e9SAndroid Build Coastguard Worker "error" : "warning";
3260*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < N; ++i) {
3261*d57664e9SAndroid Build Coastguard Worker if (!validResources[i]) {
3262*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
3263*d57664e9SAndroid Build Coastguard Worker if (c != NULL) {
3264*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "%s: no entries written for %s/%s (0x%08zx)\n", log_prefix,
3265*d57664e9SAndroid Build Coastguard Worker String8(typeName).c_str(), String8(c->getName()).c_str(),
3266*d57664e9SAndroid Build Coastguard Worker Res_MAKEID(p->getAssignedId() - 1, ti, i));
3267*d57664e9SAndroid Build Coastguard Worker }
3268*d57664e9SAndroid Build Coastguard Worker missing_entry = true;
3269*d57664e9SAndroid Build Coastguard Worker }
3270*d57664e9SAndroid Build Coastguard Worker }
3271*d57664e9SAndroid Build Coastguard Worker if (bundle->getErrorOnMissingConfigEntry() && missing_entry) {
3272*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "Error: Missing entries, quit!\n");
3273*d57664e9SAndroid Build Coastguard Worker return NOT_ENOUGH_DATA;
3274*d57664e9SAndroid Build Coastguard Worker }
3275*d57664e9SAndroid Build Coastguard Worker }
3276*d57664e9SAndroid Build Coastguard Worker }
3277*d57664e9SAndroid Build Coastguard Worker
3278*d57664e9SAndroid Build Coastguard Worker // Fill in the rest of the package information.
3279*d57664e9SAndroid Build Coastguard Worker header = (ResTable_package*)data->editData();
3280*d57664e9SAndroid Build Coastguard Worker header->header.size = htodl(data->getSize());
3281*d57664e9SAndroid Build Coastguard Worker header->typeStrings = htodl(typeStringsStart);
3282*d57664e9SAndroid Build Coastguard Worker header->lastPublicType = htodl(p->getTypeStrings().size());
3283*d57664e9SAndroid Build Coastguard Worker header->keyStrings = htodl(keyStringsStart);
3284*d57664e9SAndroid Build Coastguard Worker header->lastPublicKey = htodl(p->getKeyStrings().size());
3285*d57664e9SAndroid Build Coastguard Worker
3286*d57664e9SAndroid Build Coastguard Worker flatPackages.add(data);
3287*d57664e9SAndroid Build Coastguard Worker }
3288*d57664e9SAndroid Build Coastguard Worker
3289*d57664e9SAndroid Build Coastguard Worker // And now write out the final chunks.
3290*d57664e9SAndroid Build Coastguard Worker const size_t dataStart = dest->getSize();
3291*d57664e9SAndroid Build Coastguard Worker
3292*d57664e9SAndroid Build Coastguard Worker {
3293*d57664e9SAndroid Build Coastguard Worker // blah
3294*d57664e9SAndroid Build Coastguard Worker ResTable_header header;
3295*d57664e9SAndroid Build Coastguard Worker memset(&header, 0, sizeof(header));
3296*d57664e9SAndroid Build Coastguard Worker header.header.type = htods(RES_TABLE_TYPE);
3297*d57664e9SAndroid Build Coastguard Worker header.header.headerSize = htods(sizeof(header));
3298*d57664e9SAndroid Build Coastguard Worker header.packageCount = htodl(flatPackages.size());
3299*d57664e9SAndroid Build Coastguard Worker status_t err = dest->writeData(&header, sizeof(header));
3300*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3301*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating ResTable_header\n");
3302*d57664e9SAndroid Build Coastguard Worker return err;
3303*d57664e9SAndroid Build Coastguard Worker }
3304*d57664e9SAndroid Build Coastguard Worker }
3305*d57664e9SAndroid Build Coastguard Worker
3306*d57664e9SAndroid Build Coastguard Worker ssize_t strStart = dest->getSize();
3307*d57664e9SAndroid Build Coastguard Worker status_t err = valueStrings.writeStringBlock(dest);
3308*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3309*d57664e9SAndroid Build Coastguard Worker return err;
3310*d57664e9SAndroid Build Coastguard Worker }
3311*d57664e9SAndroid Build Coastguard Worker
3312*d57664e9SAndroid Build Coastguard Worker ssize_t amt = (dest->getSize()-strStart);
3313*d57664e9SAndroid Build Coastguard Worker strAmt += amt;
3314*d57664e9SAndroid Build Coastguard Worker if (kPrintStringMetrics) {
3315*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "**** value strings: %zd\n", amt);
3316*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "**** total strings: %zd\n", amt);
3317*d57664e9SAndroid Build Coastguard Worker }
3318*d57664e9SAndroid Build Coastguard Worker
3319*d57664e9SAndroid Build Coastguard Worker for (pi=0; pi<flatPackages.size(); pi++) {
3320*d57664e9SAndroid Build Coastguard Worker err = dest->writeData(flatPackages[pi]->getData(),
3321*d57664e9SAndroid Build Coastguard Worker flatPackages[pi]->getSize());
3322*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3323*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating package chunk for ResTable_header\n");
3324*d57664e9SAndroid Build Coastguard Worker return err;
3325*d57664e9SAndroid Build Coastguard Worker }
3326*d57664e9SAndroid Build Coastguard Worker }
3327*d57664e9SAndroid Build Coastguard Worker
3328*d57664e9SAndroid Build Coastguard Worker ResTable_header* header = (ResTable_header*)
3329*d57664e9SAndroid Build Coastguard Worker (((uint8_t*)dest->getData()) + dataStart);
3330*d57664e9SAndroid Build Coastguard Worker header->header.size = htodl(dest->getSize() - dataStart);
3331*d57664e9SAndroid Build Coastguard Worker
3332*d57664e9SAndroid Build Coastguard Worker if (kPrintStringMetrics) {
3333*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "**** total resource table size: %zu / %zu%% strings\n",
3334*d57664e9SAndroid Build Coastguard Worker dest->getSize(), (size_t)(strAmt*100)/dest->getSize());
3335*d57664e9SAndroid Build Coastguard Worker }
3336*d57664e9SAndroid Build Coastguard Worker
3337*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3338*d57664e9SAndroid Build Coastguard Worker }
3339*d57664e9SAndroid Build Coastguard Worker
flattenLibraryTable(const sp<AaptFile> & dest,const Vector<sp<Package>> & libs)3340*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs) {
3341*d57664e9SAndroid Build Coastguard Worker // Write out the library table if necessary
3342*d57664e9SAndroid Build Coastguard Worker if (libs.size() > 0) {
3343*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
3344*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "Writing library reference table\n");
3345*d57664e9SAndroid Build Coastguard Worker }
3346*d57664e9SAndroid Build Coastguard Worker
3347*d57664e9SAndroid Build Coastguard Worker const size_t libStart = dest->getSize();
3348*d57664e9SAndroid Build Coastguard Worker const size_t count = libs.size();
3349*d57664e9SAndroid Build Coastguard Worker ResTable_lib_header* libHeader = (ResTable_lib_header*) dest->editDataInRange(
3350*d57664e9SAndroid Build Coastguard Worker libStart, sizeof(ResTable_lib_header));
3351*d57664e9SAndroid Build Coastguard Worker
3352*d57664e9SAndroid Build Coastguard Worker memset(libHeader, 0, sizeof(*libHeader));
3353*d57664e9SAndroid Build Coastguard Worker libHeader->header.type = htods(RES_TABLE_LIBRARY_TYPE);
3354*d57664e9SAndroid Build Coastguard Worker libHeader->header.headerSize = htods(sizeof(*libHeader));
3355*d57664e9SAndroid Build Coastguard Worker libHeader->header.size = htodl(sizeof(*libHeader) + (sizeof(ResTable_lib_entry) * count));
3356*d57664e9SAndroid Build Coastguard Worker libHeader->count = htodl(count);
3357*d57664e9SAndroid Build Coastguard Worker
3358*d57664e9SAndroid Build Coastguard Worker // Write the library entries
3359*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < count; i++) {
3360*d57664e9SAndroid Build Coastguard Worker const size_t entryStart = dest->getSize();
3361*d57664e9SAndroid Build Coastguard Worker sp<Package> libPackage = libs[i];
3362*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
3363*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, " Entry %s -> 0x%02x\n",
3364*d57664e9SAndroid Build Coastguard Worker String8(libPackage->getName()).c_str(),
3365*d57664e9SAndroid Build Coastguard Worker (uint8_t)libPackage->getAssignedId());
3366*d57664e9SAndroid Build Coastguard Worker }
3367*d57664e9SAndroid Build Coastguard Worker
3368*d57664e9SAndroid Build Coastguard Worker ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(
3369*d57664e9SAndroid Build Coastguard Worker entryStart, sizeof(ResTable_lib_entry));
3370*d57664e9SAndroid Build Coastguard Worker memset(entry, 0, sizeof(*entry));
3371*d57664e9SAndroid Build Coastguard Worker entry->packageId = htodl(libPackage->getAssignedId());
3372*d57664e9SAndroid Build Coastguard Worker strcpy16_htod(entry->packageName, libPackage->getName().c_str());
3373*d57664e9SAndroid Build Coastguard Worker }
3374*d57664e9SAndroid Build Coastguard Worker }
3375*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3376*d57664e9SAndroid Build Coastguard Worker }
3377*d57664e9SAndroid Build Coastguard Worker
writePublicDefinitions(const String16 & package,FILE * fp)3378*d57664e9SAndroid Build Coastguard Worker void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp)
3379*d57664e9SAndroid Build Coastguard Worker {
3380*d57664e9SAndroid Build Coastguard Worker fprintf(fp,
3381*d57664e9SAndroid Build Coastguard Worker "<!-- This file contains <public> resource definitions for all\n"
3382*d57664e9SAndroid Build Coastguard Worker " resources that were generated from the source data. -->\n"
3383*d57664e9SAndroid Build Coastguard Worker "\n"
3384*d57664e9SAndroid Build Coastguard Worker "<resources>\n");
3385*d57664e9SAndroid Build Coastguard Worker
3386*d57664e9SAndroid Build Coastguard Worker writePublicDefinitions(package, fp, true);
3387*d57664e9SAndroid Build Coastguard Worker writePublicDefinitions(package, fp, false);
3388*d57664e9SAndroid Build Coastguard Worker
3389*d57664e9SAndroid Build Coastguard Worker fprintf(fp,
3390*d57664e9SAndroid Build Coastguard Worker "\n"
3391*d57664e9SAndroid Build Coastguard Worker "</resources>\n");
3392*d57664e9SAndroid Build Coastguard Worker }
3393*d57664e9SAndroid Build Coastguard Worker
writePublicDefinitions(const String16 & package,FILE * fp,bool pub)3394*d57664e9SAndroid Build Coastguard Worker void ResourceTable::writePublicDefinitions(const String16& package, FILE* fp, bool pub)
3395*d57664e9SAndroid Build Coastguard Worker {
3396*d57664e9SAndroid Build Coastguard Worker bool didHeader = false;
3397*d57664e9SAndroid Build Coastguard Worker
3398*d57664e9SAndroid Build Coastguard Worker sp<Package> pkg = mPackages.valueFor(package);
3399*d57664e9SAndroid Build Coastguard Worker if (pkg != NULL) {
3400*d57664e9SAndroid Build Coastguard Worker const size_t NT = pkg->getOrderedTypes().size();
3401*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<NT; i++) {
3402*d57664e9SAndroid Build Coastguard Worker sp<Type> t = pkg->getOrderedTypes().itemAt(i);
3403*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
3404*d57664e9SAndroid Build Coastguard Worker continue;
3405*d57664e9SAndroid Build Coastguard Worker }
3406*d57664e9SAndroid Build Coastguard Worker
3407*d57664e9SAndroid Build Coastguard Worker bool didType = false;
3408*d57664e9SAndroid Build Coastguard Worker
3409*d57664e9SAndroid Build Coastguard Worker const size_t NC = t->getOrderedConfigs().size();
3410*d57664e9SAndroid Build Coastguard Worker for (size_t j=0; j<NC; j++) {
3411*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(j);
3412*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
3413*d57664e9SAndroid Build Coastguard Worker continue;
3414*d57664e9SAndroid Build Coastguard Worker }
3415*d57664e9SAndroid Build Coastguard Worker
3416*d57664e9SAndroid Build Coastguard Worker if (c->getPublic() != pub) {
3417*d57664e9SAndroid Build Coastguard Worker continue;
3418*d57664e9SAndroid Build Coastguard Worker }
3419*d57664e9SAndroid Build Coastguard Worker
3420*d57664e9SAndroid Build Coastguard Worker if (!didType) {
3421*d57664e9SAndroid Build Coastguard Worker fprintf(fp, "\n");
3422*d57664e9SAndroid Build Coastguard Worker didType = true;
3423*d57664e9SAndroid Build Coastguard Worker }
3424*d57664e9SAndroid Build Coastguard Worker if (!didHeader) {
3425*d57664e9SAndroid Build Coastguard Worker if (pub) {
3426*d57664e9SAndroid Build Coastguard Worker fprintf(fp," <!-- PUBLIC SECTION. These resources have been declared public.\n");
3427*d57664e9SAndroid Build Coastguard Worker fprintf(fp," Changes to these definitions will break binary compatibility. -->\n\n");
3428*d57664e9SAndroid Build Coastguard Worker } else {
3429*d57664e9SAndroid Build Coastguard Worker fprintf(fp," <!-- PRIVATE SECTION. These resources have not been declared public.\n");
3430*d57664e9SAndroid Build Coastguard Worker fprintf(fp," You can make them public my moving these lines into a file in res/values. -->\n\n");
3431*d57664e9SAndroid Build Coastguard Worker }
3432*d57664e9SAndroid Build Coastguard Worker didHeader = true;
3433*d57664e9SAndroid Build Coastguard Worker }
3434*d57664e9SAndroid Build Coastguard Worker if (!pub) {
3435*d57664e9SAndroid Build Coastguard Worker const size_t NE = c->getEntries().size();
3436*d57664e9SAndroid Build Coastguard Worker for (size_t k=0; k<NE; k++) {
3437*d57664e9SAndroid Build Coastguard Worker const SourcePos& pos = c->getEntries().valueAt(k)->getPos();
3438*d57664e9SAndroid Build Coastguard Worker if (pos.file != "") {
3439*d57664e9SAndroid Build Coastguard Worker fprintf(fp," <!-- Declared at %s:%d -->\n",
3440*d57664e9SAndroid Build Coastguard Worker pos.file.c_str(), pos.line);
3441*d57664e9SAndroid Build Coastguard Worker }
3442*d57664e9SAndroid Build Coastguard Worker }
3443*d57664e9SAndroid Build Coastguard Worker }
3444*d57664e9SAndroid Build Coastguard Worker fprintf(fp, " <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n",
3445*d57664e9SAndroid Build Coastguard Worker String8(t->getName()).c_str(),
3446*d57664e9SAndroid Build Coastguard Worker String8(c->getName()).c_str(),
3447*d57664e9SAndroid Build Coastguard Worker getResId(pkg, t, c->getEntryIndex()));
3448*d57664e9SAndroid Build Coastguard Worker }
3449*d57664e9SAndroid Build Coastguard Worker }
3450*d57664e9SAndroid Build Coastguard Worker }
3451*d57664e9SAndroid Build Coastguard Worker }
3452*d57664e9SAndroid Build Coastguard Worker
Item(const SourcePos & _sourcePos,bool _isId,const String16 & _value,const Vector<StringPool::entry_style_span> * _style,int32_t _format)3453*d57664e9SAndroid Build Coastguard Worker ResourceTable::Item::Item(const SourcePos& _sourcePos,
3454*d57664e9SAndroid Build Coastguard Worker bool _isId,
3455*d57664e9SAndroid Build Coastguard Worker const String16& _value,
3456*d57664e9SAndroid Build Coastguard Worker const Vector<StringPool::entry_style_span>* _style,
3457*d57664e9SAndroid Build Coastguard Worker int32_t _format)
3458*d57664e9SAndroid Build Coastguard Worker : sourcePos(_sourcePos)
3459*d57664e9SAndroid Build Coastguard Worker , isId(_isId)
3460*d57664e9SAndroid Build Coastguard Worker , value(_value)
3461*d57664e9SAndroid Build Coastguard Worker , format(_format)
3462*d57664e9SAndroid Build Coastguard Worker , bagKeyId(0)
3463*d57664e9SAndroid Build Coastguard Worker , evaluating(false)
3464*d57664e9SAndroid Build Coastguard Worker {
3465*d57664e9SAndroid Build Coastguard Worker if (_style) {
3466*d57664e9SAndroid Build Coastguard Worker style = *_style;
3467*d57664e9SAndroid Build Coastguard Worker }
3468*d57664e9SAndroid Build Coastguard Worker }
3469*d57664e9SAndroid Build Coastguard Worker
Entry(const Entry & entry)3470*d57664e9SAndroid Build Coastguard Worker ResourceTable::Entry::Entry(const Entry& entry)
3471*d57664e9SAndroid Build Coastguard Worker : RefBase()
3472*d57664e9SAndroid Build Coastguard Worker , mName(entry.mName)
3473*d57664e9SAndroid Build Coastguard Worker , mParent(entry.mParent)
3474*d57664e9SAndroid Build Coastguard Worker , mType(entry.mType)
3475*d57664e9SAndroid Build Coastguard Worker , mItem(entry.mItem)
3476*d57664e9SAndroid Build Coastguard Worker , mItemFormat(entry.mItemFormat)
3477*d57664e9SAndroid Build Coastguard Worker , mBag(entry.mBag)
3478*d57664e9SAndroid Build Coastguard Worker , mNameIndex(entry.mNameIndex)
3479*d57664e9SAndroid Build Coastguard Worker , mParentId(entry.mParentId)
3480*d57664e9SAndroid Build Coastguard Worker , mPos(entry.mPos) {}
3481*d57664e9SAndroid Build Coastguard Worker
operator =(const Entry & entry)3482*d57664e9SAndroid Build Coastguard Worker ResourceTable::Entry& ResourceTable::Entry::operator=(const Entry& entry) {
3483*d57664e9SAndroid Build Coastguard Worker mName = entry.mName;
3484*d57664e9SAndroid Build Coastguard Worker mParent = entry.mParent;
3485*d57664e9SAndroid Build Coastguard Worker mType = entry.mType;
3486*d57664e9SAndroid Build Coastguard Worker mItem = entry.mItem;
3487*d57664e9SAndroid Build Coastguard Worker mItemFormat = entry.mItemFormat;
3488*d57664e9SAndroid Build Coastguard Worker mBag = entry.mBag;
3489*d57664e9SAndroid Build Coastguard Worker mNameIndex = entry.mNameIndex;
3490*d57664e9SAndroid Build Coastguard Worker mParentId = entry.mParentId;
3491*d57664e9SAndroid Build Coastguard Worker mPos = entry.mPos;
3492*d57664e9SAndroid Build Coastguard Worker return *this;
3493*d57664e9SAndroid Build Coastguard Worker }
3494*d57664e9SAndroid Build Coastguard Worker
makeItABag(const SourcePos & sourcePos)3495*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::makeItABag(const SourcePos& sourcePos)
3496*d57664e9SAndroid Build Coastguard Worker {
3497*d57664e9SAndroid Build Coastguard Worker if (mType == TYPE_BAG) {
3498*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3499*d57664e9SAndroid Build Coastguard Worker }
3500*d57664e9SAndroid Build Coastguard Worker if (mType == TYPE_UNKNOWN) {
3501*d57664e9SAndroid Build Coastguard Worker mType = TYPE_BAG;
3502*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3503*d57664e9SAndroid Build Coastguard Worker }
3504*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s is already defined as a single item.\n"
3505*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.\n",
3506*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(),
3507*d57664e9SAndroid Build Coastguard Worker mItem.sourcePos.file.c_str(), mItem.sourcePos.line);
3508*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3509*d57664e9SAndroid Build Coastguard Worker }
3510*d57664e9SAndroid Build Coastguard Worker
setItem(const SourcePos & sourcePos,const String16 & value,const Vector<StringPool::entry_style_span> * style,int32_t format,const bool overwrite)3511*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::setItem(const SourcePos& sourcePos,
3512*d57664e9SAndroid Build Coastguard Worker const String16& value,
3513*d57664e9SAndroid Build Coastguard Worker const Vector<StringPool::entry_style_span>* style,
3514*d57664e9SAndroid Build Coastguard Worker int32_t format,
3515*d57664e9SAndroid Build Coastguard Worker const bool overwrite)
3516*d57664e9SAndroid Build Coastguard Worker {
3517*d57664e9SAndroid Build Coastguard Worker Item item(sourcePos, false, value, style);
3518*d57664e9SAndroid Build Coastguard Worker
3519*d57664e9SAndroid Build Coastguard Worker if (mType == TYPE_BAG) {
3520*d57664e9SAndroid Build Coastguard Worker if (mBag.size() == 0) {
3521*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s is already defined as a bag.",
3522*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str());
3523*d57664e9SAndroid Build Coastguard Worker } else {
3524*d57664e9SAndroid Build Coastguard Worker const Item& item(mBag.valueAt(0));
3525*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s is already defined as a bag.\n"
3526*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.\n",
3527*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(),
3528*d57664e9SAndroid Build Coastguard Worker item.sourcePos.file.c_str(), item.sourcePos.line);
3529*d57664e9SAndroid Build Coastguard Worker }
3530*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3531*d57664e9SAndroid Build Coastguard Worker }
3532*d57664e9SAndroid Build Coastguard Worker if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) {
3533*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s is already defined.\n"
3534*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.\n",
3535*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(),
3536*d57664e9SAndroid Build Coastguard Worker mItem.sourcePos.file.c_str(), mItem.sourcePos.line);
3537*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3538*d57664e9SAndroid Build Coastguard Worker }
3539*d57664e9SAndroid Build Coastguard Worker
3540*d57664e9SAndroid Build Coastguard Worker mType = TYPE_ITEM;
3541*d57664e9SAndroid Build Coastguard Worker mItem = item;
3542*d57664e9SAndroid Build Coastguard Worker mItemFormat = format;
3543*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3544*d57664e9SAndroid Build Coastguard Worker }
3545*d57664e9SAndroid Build Coastguard Worker
addToBag(const SourcePos & sourcePos,const String16 & key,const String16 & value,const Vector<StringPool::entry_style_span> * style,bool replace,bool isId,int32_t format)3546*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::addToBag(const SourcePos& sourcePos,
3547*d57664e9SAndroid Build Coastguard Worker const String16& key, const String16& value,
3548*d57664e9SAndroid Build Coastguard Worker const Vector<StringPool::entry_style_span>* style,
3549*d57664e9SAndroid Build Coastguard Worker bool replace, bool isId, int32_t format)
3550*d57664e9SAndroid Build Coastguard Worker {
3551*d57664e9SAndroid Build Coastguard Worker status_t err = makeItABag(sourcePos);
3552*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3553*d57664e9SAndroid Build Coastguard Worker return err;
3554*d57664e9SAndroid Build Coastguard Worker }
3555*d57664e9SAndroid Build Coastguard Worker
3556*d57664e9SAndroid Build Coastguard Worker Item item(sourcePos, isId, value, style, format);
3557*d57664e9SAndroid Build Coastguard Worker
3558*d57664e9SAndroid Build Coastguard Worker // XXX NOTE: there is an error if you try to have a bag with two keys,
3559*d57664e9SAndroid Build Coastguard Worker // one an attr and one an id, with the same name. Not something we
3560*d57664e9SAndroid Build Coastguard Worker // currently ever have to worry about.
3561*d57664e9SAndroid Build Coastguard Worker ssize_t origKey = mBag.indexOfKey(key);
3562*d57664e9SAndroid Build Coastguard Worker if (origKey >= 0) {
3563*d57664e9SAndroid Build Coastguard Worker if (!replace) {
3564*d57664e9SAndroid Build Coastguard Worker const Item& item(mBag.valueAt(origKey));
3565*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource entry %s already has bag item %s.\n"
3566*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.\n",
3567*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(), String8(key).c_str(),
3568*d57664e9SAndroid Build Coastguard Worker item.sourcePos.file.c_str(), item.sourcePos.line);
3569*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3570*d57664e9SAndroid Build Coastguard Worker }
3571*d57664e9SAndroid Build Coastguard Worker //printf("Replacing %s with %s\n",
3572*d57664e9SAndroid Build Coastguard Worker // String8(mBag.valueFor(key).value).c_str(), String8(value).c_str());
3573*d57664e9SAndroid Build Coastguard Worker mBag.replaceValueFor(key, item);
3574*d57664e9SAndroid Build Coastguard Worker }
3575*d57664e9SAndroid Build Coastguard Worker
3576*d57664e9SAndroid Build Coastguard Worker mBag.add(key, item);
3577*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3578*d57664e9SAndroid Build Coastguard Worker }
3579*d57664e9SAndroid Build Coastguard Worker
removeFromBag(const String16 & key)3580*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::removeFromBag(const String16& key) {
3581*d57664e9SAndroid Build Coastguard Worker if (mType != Entry::TYPE_BAG) {
3582*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3583*d57664e9SAndroid Build Coastguard Worker }
3584*d57664e9SAndroid Build Coastguard Worker
3585*d57664e9SAndroid Build Coastguard Worker if (mBag.removeItem(key) >= 0) {
3586*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3587*d57664e9SAndroid Build Coastguard Worker }
3588*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3589*d57664e9SAndroid Build Coastguard Worker }
3590*d57664e9SAndroid Build Coastguard Worker
emptyBag(const SourcePos & sourcePos)3591*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::emptyBag(const SourcePos& sourcePos)
3592*d57664e9SAndroid Build Coastguard Worker {
3593*d57664e9SAndroid Build Coastguard Worker status_t err = makeItABag(sourcePos);
3594*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3595*d57664e9SAndroid Build Coastguard Worker return err;
3596*d57664e9SAndroid Build Coastguard Worker }
3597*d57664e9SAndroid Build Coastguard Worker
3598*d57664e9SAndroid Build Coastguard Worker mBag.clear();
3599*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3600*d57664e9SAndroid Build Coastguard Worker }
3601*d57664e9SAndroid Build Coastguard Worker
generateAttributes(ResourceTable * table,const String16 & package)3602*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::generateAttributes(ResourceTable* table,
3603*d57664e9SAndroid Build Coastguard Worker const String16& package)
3604*d57664e9SAndroid Build Coastguard Worker {
3605*d57664e9SAndroid Build Coastguard Worker const String16 attr16("attr");
3606*d57664e9SAndroid Build Coastguard Worker const String16 id16("id");
3607*d57664e9SAndroid Build Coastguard Worker const size_t N = mBag.size();
3608*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
3609*d57664e9SAndroid Build Coastguard Worker const String16& key = mBag.keyAt(i);
3610*d57664e9SAndroid Build Coastguard Worker const Item& it = mBag.valueAt(i);
3611*d57664e9SAndroid Build Coastguard Worker if (it.isId) {
3612*d57664e9SAndroid Build Coastguard Worker if (!table->hasBagOrEntry(key, &id16, &package)) {
3613*d57664e9SAndroid Build Coastguard Worker String16 value("false");
3614*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
3615*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "Generating %s:id/%s\n",
3616*d57664e9SAndroid Build Coastguard Worker String8(package).c_str(),
3617*d57664e9SAndroid Build Coastguard Worker String8(key).c_str());
3618*d57664e9SAndroid Build Coastguard Worker }
3619*d57664e9SAndroid Build Coastguard Worker status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
3620*d57664e9SAndroid Build Coastguard Worker id16, key, value);
3621*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3622*d57664e9SAndroid Build Coastguard Worker return err;
3623*d57664e9SAndroid Build Coastguard Worker }
3624*d57664e9SAndroid Build Coastguard Worker }
3625*d57664e9SAndroid Build Coastguard Worker } else if (!table->hasBagOrEntry(key, &attr16, &package)) {
3626*d57664e9SAndroid Build Coastguard Worker
3627*d57664e9SAndroid Build Coastguard Worker #if 1
3628*d57664e9SAndroid Build Coastguard Worker // fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n",
3629*d57664e9SAndroid Build Coastguard Worker // String8(key).c_str());
3630*d57664e9SAndroid Build Coastguard Worker // const Item& item(mBag.valueAt(i));
3631*d57664e9SAndroid Build Coastguard Worker // fprintf(stderr, "Referenced from file %s line %d\n",
3632*d57664e9SAndroid Build Coastguard Worker // item.sourcePos.file.c_str(), item.sourcePos.line);
3633*d57664e9SAndroid Build Coastguard Worker // return UNKNOWN_ERROR;
3634*d57664e9SAndroid Build Coastguard Worker #else
3635*d57664e9SAndroid Build Coastguard Worker char numberStr[16];
3636*d57664e9SAndroid Build Coastguard Worker sprintf(numberStr, "%d", ResTable_map::TYPE_ANY);
3637*d57664e9SAndroid Build Coastguard Worker status_t err = table->addBag(SourcePos("<generated>", 0), package,
3638*d57664e9SAndroid Build Coastguard Worker attr16, key, String16(""),
3639*d57664e9SAndroid Build Coastguard Worker String16("^type"),
3640*d57664e9SAndroid Build Coastguard Worker String16(numberStr), NULL, NULL);
3641*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3642*d57664e9SAndroid Build Coastguard Worker return err;
3643*d57664e9SAndroid Build Coastguard Worker }
3644*d57664e9SAndroid Build Coastguard Worker #endif
3645*d57664e9SAndroid Build Coastguard Worker }
3646*d57664e9SAndroid Build Coastguard Worker }
3647*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3648*d57664e9SAndroid Build Coastguard Worker }
3649*d57664e9SAndroid Build Coastguard Worker
assignResourceIds(ResourceTable * table,const String16 &)3650*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
3651*d57664e9SAndroid Build Coastguard Worker const String16& /* package */)
3652*d57664e9SAndroid Build Coastguard Worker {
3653*d57664e9SAndroid Build Coastguard Worker bool hasErrors = false;
3654*d57664e9SAndroid Build Coastguard Worker
3655*d57664e9SAndroid Build Coastguard Worker if (mType == TYPE_BAG) {
3656*d57664e9SAndroid Build Coastguard Worker const char* errorMsg;
3657*d57664e9SAndroid Build Coastguard Worker const String16 style16("style");
3658*d57664e9SAndroid Build Coastguard Worker const String16 attr16("attr");
3659*d57664e9SAndroid Build Coastguard Worker const String16 id16("id");
3660*d57664e9SAndroid Build Coastguard Worker mParentId = 0;
3661*d57664e9SAndroid Build Coastguard Worker if (mParent.size() > 0) {
3662*d57664e9SAndroid Build Coastguard Worker mParentId = table->getResId(mParent, &style16, NULL, &errorMsg);
3663*d57664e9SAndroid Build Coastguard Worker if (mParentId == 0) {
3664*d57664e9SAndroid Build Coastguard Worker mPos.error("Error retrieving parent for item: %s '%s'.\n",
3665*d57664e9SAndroid Build Coastguard Worker errorMsg, String8(mParent).c_str());
3666*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
3667*d57664e9SAndroid Build Coastguard Worker }
3668*d57664e9SAndroid Build Coastguard Worker }
3669*d57664e9SAndroid Build Coastguard Worker const size_t N = mBag.size();
3670*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
3671*d57664e9SAndroid Build Coastguard Worker const String16& key = mBag.keyAt(i);
3672*d57664e9SAndroid Build Coastguard Worker Item& it = mBag.editValueAt(i);
3673*d57664e9SAndroid Build Coastguard Worker it.bagKeyId = table->getResId(key,
3674*d57664e9SAndroid Build Coastguard Worker it.isId ? &id16 : &attr16, NULL, &errorMsg);
3675*d57664e9SAndroid Build Coastguard Worker //printf("Bag key of %s: #%08x\n", String8(key).c_str(), it.bagKeyId);
3676*d57664e9SAndroid Build Coastguard Worker if (it.bagKeyId == 0) {
3677*d57664e9SAndroid Build Coastguard Worker it.sourcePos.error("Error: %s: %s '%s'.\n", errorMsg,
3678*d57664e9SAndroid Build Coastguard Worker String8(it.isId ? id16 : attr16).c_str(),
3679*d57664e9SAndroid Build Coastguard Worker String8(key).c_str());
3680*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
3681*d57664e9SAndroid Build Coastguard Worker }
3682*d57664e9SAndroid Build Coastguard Worker }
3683*d57664e9SAndroid Build Coastguard Worker }
3684*d57664e9SAndroid Build Coastguard Worker return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
3685*d57664e9SAndroid Build Coastguard Worker }
3686*d57664e9SAndroid Build Coastguard Worker
prepareFlatten(StringPool * strings,ResourceTable * table,const String8 * configTypeName,const ConfigDescription * config)3687*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
3688*d57664e9SAndroid Build Coastguard Worker const String8* configTypeName, const ConfigDescription* config)
3689*d57664e9SAndroid Build Coastguard Worker {
3690*d57664e9SAndroid Build Coastguard Worker if (mType == TYPE_ITEM) {
3691*d57664e9SAndroid Build Coastguard Worker Item& it = mItem;
3692*d57664e9SAndroid Build Coastguard Worker AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value));
3693*d57664e9SAndroid Build Coastguard Worker if (!table->stringToValue(&it.parsedValue, strings,
3694*d57664e9SAndroid Build Coastguard Worker it.value, false, true, 0,
3695*d57664e9SAndroid Build Coastguard Worker &it.style, NULL, &ac, mItemFormat,
3696*d57664e9SAndroid Build Coastguard Worker configTypeName, config)) {
3697*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3698*d57664e9SAndroid Build Coastguard Worker }
3699*d57664e9SAndroid Build Coastguard Worker } else if (mType == TYPE_BAG) {
3700*d57664e9SAndroid Build Coastguard Worker const size_t N = mBag.size();
3701*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
3702*d57664e9SAndroid Build Coastguard Worker const String16& key = mBag.keyAt(i);
3703*d57664e9SAndroid Build Coastguard Worker Item& it = mBag.editValueAt(i);
3704*d57664e9SAndroid Build Coastguard Worker AccessorCookie ac(it.sourcePos, String8(key), String8(it.value));
3705*d57664e9SAndroid Build Coastguard Worker if (!table->stringToValue(&it.parsedValue, strings,
3706*d57664e9SAndroid Build Coastguard Worker it.value, false, true, it.bagKeyId,
3707*d57664e9SAndroid Build Coastguard Worker &it.style, NULL, &ac, it.format,
3708*d57664e9SAndroid Build Coastguard Worker configTypeName, config)) {
3709*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3710*d57664e9SAndroid Build Coastguard Worker }
3711*d57664e9SAndroid Build Coastguard Worker }
3712*d57664e9SAndroid Build Coastguard Worker } else {
3713*d57664e9SAndroid Build Coastguard Worker mPos.error("Error: entry %s is not a single item or a bag.\n",
3714*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str());
3715*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3716*d57664e9SAndroid Build Coastguard Worker }
3717*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3718*d57664e9SAndroid Build Coastguard Worker }
3719*d57664e9SAndroid Build Coastguard Worker
remapStringValue(StringPool * strings)3720*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Entry::remapStringValue(StringPool* strings)
3721*d57664e9SAndroid Build Coastguard Worker {
3722*d57664e9SAndroid Build Coastguard Worker if (mType == TYPE_ITEM) {
3723*d57664e9SAndroid Build Coastguard Worker Item& it = mItem;
3724*d57664e9SAndroid Build Coastguard Worker if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
3725*d57664e9SAndroid Build Coastguard Worker it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
3726*d57664e9SAndroid Build Coastguard Worker }
3727*d57664e9SAndroid Build Coastguard Worker } else if (mType == TYPE_BAG) {
3728*d57664e9SAndroid Build Coastguard Worker const size_t N = mBag.size();
3729*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
3730*d57664e9SAndroid Build Coastguard Worker Item& it = mBag.editValueAt(i);
3731*d57664e9SAndroid Build Coastguard Worker if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
3732*d57664e9SAndroid Build Coastguard Worker it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
3733*d57664e9SAndroid Build Coastguard Worker }
3734*d57664e9SAndroid Build Coastguard Worker }
3735*d57664e9SAndroid Build Coastguard Worker } else {
3736*d57664e9SAndroid Build Coastguard Worker mPos.error("Error: entry %s is not a single item or a bag.\n",
3737*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str());
3738*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3739*d57664e9SAndroid Build Coastguard Worker }
3740*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3741*d57664e9SAndroid Build Coastguard Worker }
3742*d57664e9SAndroid Build Coastguard Worker
flatten(Bundle *,const sp<AaptFile> & data,bool isPublic)3743*d57664e9SAndroid Build Coastguard Worker ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp<AaptFile>& data, bool isPublic)
3744*d57664e9SAndroid Build Coastguard Worker {
3745*d57664e9SAndroid Build Coastguard Worker size_t amt = 0;
3746*d57664e9SAndroid Build Coastguard Worker ResTable_entry header;
3747*d57664e9SAndroid Build Coastguard Worker memset(&header, 0, sizeof(header));
3748*d57664e9SAndroid Build Coastguard Worker header.full.size = htods(sizeof(header));
3749*d57664e9SAndroid Build Coastguard Worker const type ty = mType;
3750*d57664e9SAndroid Build Coastguard Worker if (ty == TYPE_BAG) {
3751*d57664e9SAndroid Build Coastguard Worker header.full.flags |= htods(header.FLAG_COMPLEX);
3752*d57664e9SAndroid Build Coastguard Worker }
3753*d57664e9SAndroid Build Coastguard Worker if (isPublic) {
3754*d57664e9SAndroid Build Coastguard Worker header.full.flags |= htods(header.FLAG_PUBLIC);
3755*d57664e9SAndroid Build Coastguard Worker }
3756*d57664e9SAndroid Build Coastguard Worker header.full.key.index = htodl(mNameIndex);
3757*d57664e9SAndroid Build Coastguard Worker if (ty != TYPE_BAG) {
3758*d57664e9SAndroid Build Coastguard Worker status_t err = data->writeData(&header, sizeof(header));
3759*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3760*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n");
3761*d57664e9SAndroid Build Coastguard Worker return err;
3762*d57664e9SAndroid Build Coastguard Worker }
3763*d57664e9SAndroid Build Coastguard Worker
3764*d57664e9SAndroid Build Coastguard Worker const Item& it = mItem;
3765*d57664e9SAndroid Build Coastguard Worker Res_value par;
3766*d57664e9SAndroid Build Coastguard Worker memset(&par, 0, sizeof(par));
3767*d57664e9SAndroid Build Coastguard Worker par.size = htods(it.parsedValue.size);
3768*d57664e9SAndroid Build Coastguard Worker par.dataType = it.parsedValue.dataType;
3769*d57664e9SAndroid Build Coastguard Worker par.res0 = it.parsedValue.res0;
3770*d57664e9SAndroid Build Coastguard Worker par.data = htodl(it.parsedValue.data);
3771*d57664e9SAndroid Build Coastguard Worker #if 0
3772*d57664e9SAndroid Build Coastguard Worker printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n",
3773*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(), it.parsedValue.dataType,
3774*d57664e9SAndroid Build Coastguard Worker it.parsedValue.data, par.res0);
3775*d57664e9SAndroid Build Coastguard Worker #endif
3776*d57664e9SAndroid Build Coastguard Worker err = data->writeData(&par, it.parsedValue.size);
3777*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3778*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating Res_value\n");
3779*d57664e9SAndroid Build Coastguard Worker return err;
3780*d57664e9SAndroid Build Coastguard Worker }
3781*d57664e9SAndroid Build Coastguard Worker amt += it.parsedValue.size;
3782*d57664e9SAndroid Build Coastguard Worker } else {
3783*d57664e9SAndroid Build Coastguard Worker size_t N = mBag.size();
3784*d57664e9SAndroid Build Coastguard Worker size_t i;
3785*d57664e9SAndroid Build Coastguard Worker // Create correct ordering of items.
3786*d57664e9SAndroid Build Coastguard Worker KeyedVector<uint32_t, const Item*> items;
3787*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
3788*d57664e9SAndroid Build Coastguard Worker const Item& it = mBag.valueAt(i);
3789*d57664e9SAndroid Build Coastguard Worker items.add(it.bagKeyId, &it);
3790*d57664e9SAndroid Build Coastguard Worker }
3791*d57664e9SAndroid Build Coastguard Worker N = items.size();
3792*d57664e9SAndroid Build Coastguard Worker
3793*d57664e9SAndroid Build Coastguard Worker ResTable_map_entry mapHeader;
3794*d57664e9SAndroid Build Coastguard Worker memcpy(&mapHeader, &header, sizeof(header));
3795*d57664e9SAndroid Build Coastguard Worker mapHeader.size = htods(sizeof(mapHeader));
3796*d57664e9SAndroid Build Coastguard Worker mapHeader.parent.ident = htodl(mParentId);
3797*d57664e9SAndroid Build Coastguard Worker mapHeader.count = htodl(N);
3798*d57664e9SAndroid Build Coastguard Worker status_t err = data->writeData(&mapHeader, sizeof(mapHeader));
3799*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3800*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating ResTable_entry\n");
3801*d57664e9SAndroid Build Coastguard Worker return err;
3802*d57664e9SAndroid Build Coastguard Worker }
3803*d57664e9SAndroid Build Coastguard Worker
3804*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
3805*d57664e9SAndroid Build Coastguard Worker const Item& it = *items.valueAt(i);
3806*d57664e9SAndroid Build Coastguard Worker ResTable_map map;
3807*d57664e9SAndroid Build Coastguard Worker map.name.ident = htodl(it.bagKeyId);
3808*d57664e9SAndroid Build Coastguard Worker map.value.size = htods(it.parsedValue.size);
3809*d57664e9SAndroid Build Coastguard Worker map.value.dataType = it.parsedValue.dataType;
3810*d57664e9SAndroid Build Coastguard Worker map.value.res0 = it.parsedValue.res0;
3811*d57664e9SAndroid Build Coastguard Worker map.value.data = htodl(it.parsedValue.data);
3812*d57664e9SAndroid Build Coastguard Worker err = data->writeData(&map, sizeof(map));
3813*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
3814*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: out of memory creating Res_value\n");
3815*d57664e9SAndroid Build Coastguard Worker return err;
3816*d57664e9SAndroid Build Coastguard Worker }
3817*d57664e9SAndroid Build Coastguard Worker amt += sizeof(map);
3818*d57664e9SAndroid Build Coastguard Worker }
3819*d57664e9SAndroid Build Coastguard Worker }
3820*d57664e9SAndroid Build Coastguard Worker return amt;
3821*d57664e9SAndroid Build Coastguard Worker }
3822*d57664e9SAndroid Build Coastguard Worker
appendComment(const String16 & comment,bool onlyIfEmpty)3823*d57664e9SAndroid Build Coastguard Worker void ResourceTable::ConfigList::appendComment(const String16& comment,
3824*d57664e9SAndroid Build Coastguard Worker bool onlyIfEmpty)
3825*d57664e9SAndroid Build Coastguard Worker {
3826*d57664e9SAndroid Build Coastguard Worker if (comment.size() <= 0) {
3827*d57664e9SAndroid Build Coastguard Worker return;
3828*d57664e9SAndroid Build Coastguard Worker }
3829*d57664e9SAndroid Build Coastguard Worker if (onlyIfEmpty && mComment.size() > 0) {
3830*d57664e9SAndroid Build Coastguard Worker return;
3831*d57664e9SAndroid Build Coastguard Worker }
3832*d57664e9SAndroid Build Coastguard Worker if (mComment.size() > 0) {
3833*d57664e9SAndroid Build Coastguard Worker mComment.append(String16("\n"));
3834*d57664e9SAndroid Build Coastguard Worker }
3835*d57664e9SAndroid Build Coastguard Worker mComment.append(comment);
3836*d57664e9SAndroid Build Coastguard Worker }
3837*d57664e9SAndroid Build Coastguard Worker
appendTypeComment(const String16 & comment)3838*d57664e9SAndroid Build Coastguard Worker void ResourceTable::ConfigList::appendTypeComment(const String16& comment)
3839*d57664e9SAndroid Build Coastguard Worker {
3840*d57664e9SAndroid Build Coastguard Worker if (comment.size() <= 0) {
3841*d57664e9SAndroid Build Coastguard Worker return;
3842*d57664e9SAndroid Build Coastguard Worker }
3843*d57664e9SAndroid Build Coastguard Worker if (mTypeComment.size() > 0) {
3844*d57664e9SAndroid Build Coastguard Worker mTypeComment.append(String16("\n"));
3845*d57664e9SAndroid Build Coastguard Worker }
3846*d57664e9SAndroid Build Coastguard Worker mTypeComment.append(comment);
3847*d57664e9SAndroid Build Coastguard Worker }
3848*d57664e9SAndroid Build Coastguard Worker
addPublic(const SourcePos & sourcePos,const String16 & name,const uint32_t ident)3849*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
3850*d57664e9SAndroid Build Coastguard Worker const String16& name,
3851*d57664e9SAndroid Build Coastguard Worker const uint32_t ident)
3852*d57664e9SAndroid Build Coastguard Worker {
3853*d57664e9SAndroid Build Coastguard Worker #if 0
3854*d57664e9SAndroid Build Coastguard Worker int32_t entryIdx = Res_GETENTRY(ident);
3855*d57664e9SAndroid Build Coastguard Worker if (entryIdx < 0) {
3856*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n",
3857*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(), String8(name).c_str(), ident);
3858*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3859*d57664e9SAndroid Build Coastguard Worker }
3860*d57664e9SAndroid Build Coastguard Worker #endif
3861*d57664e9SAndroid Build Coastguard Worker
3862*d57664e9SAndroid Build Coastguard Worker int32_t typeIdx = Res_GETTYPE(ident);
3863*d57664e9SAndroid Build Coastguard Worker if (typeIdx >= 0) {
3864*d57664e9SAndroid Build Coastguard Worker typeIdx++;
3865*d57664e9SAndroid Build Coastguard Worker if (mPublicIndex > 0 && mPublicIndex != typeIdx) {
3866*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Public resource %s/%s has conflicting type codes for its"
3867*d57664e9SAndroid Build Coastguard Worker " public identifiers (0x%x vs 0x%x).\n",
3868*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(), String8(name).c_str(),
3869*d57664e9SAndroid Build Coastguard Worker mPublicIndex, typeIdx);
3870*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3871*d57664e9SAndroid Build Coastguard Worker }
3872*d57664e9SAndroid Build Coastguard Worker mPublicIndex = typeIdx;
3873*d57664e9SAndroid Build Coastguard Worker }
3874*d57664e9SAndroid Build Coastguard Worker
3875*d57664e9SAndroid Build Coastguard Worker if (mFirstPublicSourcePos == NULL) {
3876*d57664e9SAndroid Build Coastguard Worker mFirstPublicSourcePos = new SourcePos(sourcePos);
3877*d57664e9SAndroid Build Coastguard Worker }
3878*d57664e9SAndroid Build Coastguard Worker
3879*d57664e9SAndroid Build Coastguard Worker if (mPublic.indexOfKey(name) < 0) {
3880*d57664e9SAndroid Build Coastguard Worker mPublic.add(name, Public(sourcePos, String16(), ident));
3881*d57664e9SAndroid Build Coastguard Worker } else {
3882*d57664e9SAndroid Build Coastguard Worker Public& p = mPublic.editValueFor(name);
3883*d57664e9SAndroid Build Coastguard Worker if (p.ident != ident) {
3884*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Public resource %s/%s has conflicting public identifiers"
3885*d57664e9SAndroid Build Coastguard Worker " (0x%08x vs 0x%08x).\n"
3886*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.\n",
3887*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(), String8(name).c_str(), p.ident, ident,
3888*d57664e9SAndroid Build Coastguard Worker p.sourcePos.file.c_str(), p.sourcePos.line);
3889*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
3890*d57664e9SAndroid Build Coastguard Worker }
3891*d57664e9SAndroid Build Coastguard Worker }
3892*d57664e9SAndroid Build Coastguard Worker
3893*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
3894*d57664e9SAndroid Build Coastguard Worker }
3895*d57664e9SAndroid Build Coastguard Worker
canAddEntry(const String16 & name)3896*d57664e9SAndroid Build Coastguard Worker void ResourceTable::Type::canAddEntry(const String16& name)
3897*d57664e9SAndroid Build Coastguard Worker {
3898*d57664e9SAndroid Build Coastguard Worker mCanAddEntries.add(name);
3899*d57664e9SAndroid Build Coastguard Worker }
3900*d57664e9SAndroid Build Coastguard Worker
getEntry(const String16 & entry,const SourcePos & sourcePos,const ResTable_config * config,bool doSetIndex,bool overlay,bool autoAddOverlay)3901*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
3902*d57664e9SAndroid Build Coastguard Worker const SourcePos& sourcePos,
3903*d57664e9SAndroid Build Coastguard Worker const ResTable_config* config,
3904*d57664e9SAndroid Build Coastguard Worker bool doSetIndex,
3905*d57664e9SAndroid Build Coastguard Worker bool overlay,
3906*d57664e9SAndroid Build Coastguard Worker bool autoAddOverlay)
3907*d57664e9SAndroid Build Coastguard Worker {
3908*d57664e9SAndroid Build Coastguard Worker int pos = -1;
3909*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = mConfigs.valueFor(entry);
3910*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
3911*d57664e9SAndroid Build Coastguard Worker if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) {
3912*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Resource at %s appears in overlay but not"
3913*d57664e9SAndroid Build Coastguard Worker " in the base package; use <add-resource> to add.\n",
3914*d57664e9SAndroid Build Coastguard Worker String8(entry).c_str());
3915*d57664e9SAndroid Build Coastguard Worker return NULL;
3916*d57664e9SAndroid Build Coastguard Worker }
3917*d57664e9SAndroid Build Coastguard Worker c = new ConfigList(entry, sourcePos);
3918*d57664e9SAndroid Build Coastguard Worker mConfigs.add(entry, c);
3919*d57664e9SAndroid Build Coastguard Worker pos = (int)mOrderedConfigs.size();
3920*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.add(c);
3921*d57664e9SAndroid Build Coastguard Worker if (doSetIndex) {
3922*d57664e9SAndroid Build Coastguard Worker c->setEntryIndex(pos);
3923*d57664e9SAndroid Build Coastguard Worker }
3924*d57664e9SAndroid Build Coastguard Worker }
3925*d57664e9SAndroid Build Coastguard Worker
3926*d57664e9SAndroid Build Coastguard Worker ConfigDescription cdesc;
3927*d57664e9SAndroid Build Coastguard Worker if (config) cdesc = *config;
3928*d57664e9SAndroid Build Coastguard Worker
3929*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = c->getEntries().valueFor(cdesc);
3930*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
3931*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
3932*d57664e9SAndroid Build Coastguard Worker if (config != NULL) {
3933*d57664e9SAndroid Build Coastguard Worker printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
3934*d57664e9SAndroid Build Coastguard Worker "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
3935*d57664e9SAndroid Build Coastguard Worker "sw%ddp w%ddp h%ddp layout:%d\n",
3936*d57664e9SAndroid Build Coastguard Worker sourcePos.file.c_str(), sourcePos.line,
3937*d57664e9SAndroid Build Coastguard Worker config->mcc, config->mnc,
3938*d57664e9SAndroid Build Coastguard Worker config->language[0] ? config->language[0] : '-',
3939*d57664e9SAndroid Build Coastguard Worker config->language[1] ? config->language[1] : '-',
3940*d57664e9SAndroid Build Coastguard Worker config->country[0] ? config->country[0] : '-',
3941*d57664e9SAndroid Build Coastguard Worker config->country[1] ? config->country[1] : '-',
3942*d57664e9SAndroid Build Coastguard Worker config->orientation,
3943*d57664e9SAndroid Build Coastguard Worker config->touchscreen,
3944*d57664e9SAndroid Build Coastguard Worker config->density,
3945*d57664e9SAndroid Build Coastguard Worker config->keyboard,
3946*d57664e9SAndroid Build Coastguard Worker config->inputFlags,
3947*d57664e9SAndroid Build Coastguard Worker config->navigation,
3948*d57664e9SAndroid Build Coastguard Worker config->screenWidth,
3949*d57664e9SAndroid Build Coastguard Worker config->screenHeight,
3950*d57664e9SAndroid Build Coastguard Worker config->smallestScreenWidthDp,
3951*d57664e9SAndroid Build Coastguard Worker config->screenWidthDp,
3952*d57664e9SAndroid Build Coastguard Worker config->screenHeightDp,
3953*d57664e9SAndroid Build Coastguard Worker config->screenLayout);
3954*d57664e9SAndroid Build Coastguard Worker } else {
3955*d57664e9SAndroid Build Coastguard Worker printf("New entry at %s:%d: NULL config\n",
3956*d57664e9SAndroid Build Coastguard Worker sourcePos.file.c_str(), sourcePos.line);
3957*d57664e9SAndroid Build Coastguard Worker }
3958*d57664e9SAndroid Build Coastguard Worker }
3959*d57664e9SAndroid Build Coastguard Worker e = new Entry(entry, sourcePos);
3960*d57664e9SAndroid Build Coastguard Worker c->addEntry(cdesc, e);
3961*d57664e9SAndroid Build Coastguard Worker /*
3962*d57664e9SAndroid Build Coastguard Worker if (doSetIndex) {
3963*d57664e9SAndroid Build Coastguard Worker if (pos < 0) {
3964*d57664e9SAndroid Build Coastguard Worker for (pos=0; pos<(int)mOrderedConfigs.size(); pos++) {
3965*d57664e9SAndroid Build Coastguard Worker if (mOrderedConfigs[pos] == c) {
3966*d57664e9SAndroid Build Coastguard Worker break;
3967*d57664e9SAndroid Build Coastguard Worker }
3968*d57664e9SAndroid Build Coastguard Worker }
3969*d57664e9SAndroid Build Coastguard Worker if (pos >= (int)mOrderedConfigs.size()) {
3970*d57664e9SAndroid Build Coastguard Worker sourcePos.error("Internal error: config not found in mOrderedConfigs when adding entry");
3971*d57664e9SAndroid Build Coastguard Worker return NULL;
3972*d57664e9SAndroid Build Coastguard Worker }
3973*d57664e9SAndroid Build Coastguard Worker }
3974*d57664e9SAndroid Build Coastguard Worker e->setEntryIndex(pos);
3975*d57664e9SAndroid Build Coastguard Worker }
3976*d57664e9SAndroid Build Coastguard Worker */
3977*d57664e9SAndroid Build Coastguard Worker }
3978*d57664e9SAndroid Build Coastguard Worker
3979*d57664e9SAndroid Build Coastguard Worker return e;
3980*d57664e9SAndroid Build Coastguard Worker }
3981*d57664e9SAndroid Build Coastguard Worker
removeEntry(const String16 & entry)3982*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::ConfigList> ResourceTable::Type::removeEntry(const String16& entry) {
3983*d57664e9SAndroid Build Coastguard Worker ssize_t idx = mConfigs.indexOfKey(entry);
3984*d57664e9SAndroid Build Coastguard Worker if (idx < 0) {
3985*d57664e9SAndroid Build Coastguard Worker return NULL;
3986*d57664e9SAndroid Build Coastguard Worker }
3987*d57664e9SAndroid Build Coastguard Worker
3988*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> removed = mConfigs.valueAt(idx);
3989*d57664e9SAndroid Build Coastguard Worker mConfigs.removeItemsAt(idx);
3990*d57664e9SAndroid Build Coastguard Worker
3991*d57664e9SAndroid Build Coastguard Worker Vector<sp<ConfigList> >::iterator iter = std::find(
3992*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.begin(), mOrderedConfigs.end(), removed);
3993*d57664e9SAndroid Build Coastguard Worker if (iter != mOrderedConfigs.end()) {
3994*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.erase(iter);
3995*d57664e9SAndroid Build Coastguard Worker }
3996*d57664e9SAndroid Build Coastguard Worker
3997*d57664e9SAndroid Build Coastguard Worker mPublic.removeItem(entry);
3998*d57664e9SAndroid Build Coastguard Worker return removed;
3999*d57664e9SAndroid Build Coastguard Worker }
4000*d57664e9SAndroid Build Coastguard Worker
getUniqueConfigs() const4001*d57664e9SAndroid Build Coastguard Worker SortedVector<ConfigDescription> ResourceTable::Type::getUniqueConfigs() const {
4002*d57664e9SAndroid Build Coastguard Worker SortedVector<ConfigDescription> unique;
4003*d57664e9SAndroid Build Coastguard Worker const size_t entryCount = mOrderedConfigs.size();
4004*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < entryCount; i++) {
4005*d57664e9SAndroid Build Coastguard Worker if (mOrderedConfigs[i] == NULL) {
4006*d57664e9SAndroid Build Coastguard Worker continue;
4007*d57664e9SAndroid Build Coastguard Worker }
4008*d57664e9SAndroid Build Coastguard Worker const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configs =
4009*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs[i]->getEntries();
4010*d57664e9SAndroid Build Coastguard Worker const size_t configCount = configs.size();
4011*d57664e9SAndroid Build Coastguard Worker for (size_t j = 0; j < configCount; j++) {
4012*d57664e9SAndroid Build Coastguard Worker unique.add(configs.keyAt(j));
4013*d57664e9SAndroid Build Coastguard Worker }
4014*d57664e9SAndroid Build Coastguard Worker }
4015*d57664e9SAndroid Build Coastguard Worker return unique;
4016*d57664e9SAndroid Build Coastguard Worker }
4017*d57664e9SAndroid Build Coastguard Worker
applyPublicEntryOrder()4018*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Type::applyPublicEntryOrder()
4019*d57664e9SAndroid Build Coastguard Worker {
4020*d57664e9SAndroid Build Coastguard Worker size_t N = mOrderedConfigs.size();
4021*d57664e9SAndroid Build Coastguard Worker Vector<sp<ConfigList> > origOrder(mOrderedConfigs);
4022*d57664e9SAndroid Build Coastguard Worker bool hasError = false;
4023*d57664e9SAndroid Build Coastguard Worker
4024*d57664e9SAndroid Build Coastguard Worker size_t i;
4025*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4026*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.replaceAt(NULL, i);
4027*d57664e9SAndroid Build Coastguard Worker }
4028*d57664e9SAndroid Build Coastguard Worker
4029*d57664e9SAndroid Build Coastguard Worker const size_t NP = mPublic.size();
4030*d57664e9SAndroid Build Coastguard Worker //printf("Ordering %d configs from %d public defs\n", N, NP);
4031*d57664e9SAndroid Build Coastguard Worker size_t j;
4032*d57664e9SAndroid Build Coastguard Worker for (j=0; j<NP; j++) {
4033*d57664e9SAndroid Build Coastguard Worker const String16& name = mPublic.keyAt(j);
4034*d57664e9SAndroid Build Coastguard Worker const Public& p = mPublic.valueAt(j);
4035*d57664e9SAndroid Build Coastguard Worker int32_t idx = Res_GETENTRY(p.ident);
4036*d57664e9SAndroid Build Coastguard Worker //printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n",
4037*d57664e9SAndroid Build Coastguard Worker // String8(mName).c_str(), String8(name).c_str(), p.ident, N);
4038*d57664e9SAndroid Build Coastguard Worker bool found = false;
4039*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4040*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> e = origOrder.itemAt(i);
4041*d57664e9SAndroid Build Coastguard Worker //printf("#%d: \"%s\"\n", i, String8(e->getName()).c_str());
4042*d57664e9SAndroid Build Coastguard Worker if (e->getName() == name) {
4043*d57664e9SAndroid Build Coastguard Worker if (idx >= (int32_t)mOrderedConfigs.size()) {
4044*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.resize(idx + 1);
4045*d57664e9SAndroid Build Coastguard Worker }
4046*d57664e9SAndroid Build Coastguard Worker
4047*d57664e9SAndroid Build Coastguard Worker if (mOrderedConfigs.itemAt(idx) == NULL) {
4048*d57664e9SAndroid Build Coastguard Worker e->setPublic(true);
4049*d57664e9SAndroid Build Coastguard Worker e->setPublicSourcePos(p.sourcePos);
4050*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.replaceAt(e, idx);
4051*d57664e9SAndroid Build Coastguard Worker origOrder.removeAt(i);
4052*d57664e9SAndroid Build Coastguard Worker N--;
4053*d57664e9SAndroid Build Coastguard Worker found = true;
4054*d57664e9SAndroid Build Coastguard Worker break;
4055*d57664e9SAndroid Build Coastguard Worker } else {
4056*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> oe = mOrderedConfigs.itemAt(idx);
4057*d57664e9SAndroid Build Coastguard Worker
4058*d57664e9SAndroid Build Coastguard Worker p.sourcePos.error("Multiple entry names declared for public entry"
4059*d57664e9SAndroid Build Coastguard Worker " identifier 0x%x in type %s (%s vs %s).\n"
4060*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.",
4061*d57664e9SAndroid Build Coastguard Worker idx+1, String8(mName).c_str(),
4062*d57664e9SAndroid Build Coastguard Worker String8(oe->getName()).c_str(),
4063*d57664e9SAndroid Build Coastguard Worker String8(name).c_str(),
4064*d57664e9SAndroid Build Coastguard Worker oe->getPublicSourcePos().file.c_str(),
4065*d57664e9SAndroid Build Coastguard Worker oe->getPublicSourcePos().line);
4066*d57664e9SAndroid Build Coastguard Worker hasError = true;
4067*d57664e9SAndroid Build Coastguard Worker }
4068*d57664e9SAndroid Build Coastguard Worker }
4069*d57664e9SAndroid Build Coastguard Worker }
4070*d57664e9SAndroid Build Coastguard Worker
4071*d57664e9SAndroid Build Coastguard Worker if (!found) {
4072*d57664e9SAndroid Build Coastguard Worker p.sourcePos.error("Public symbol %s/%s declared here is not defined.",
4073*d57664e9SAndroid Build Coastguard Worker String8(mName).c_str(), String8(name).c_str());
4074*d57664e9SAndroid Build Coastguard Worker hasError = true;
4075*d57664e9SAndroid Build Coastguard Worker }
4076*d57664e9SAndroid Build Coastguard Worker }
4077*d57664e9SAndroid Build Coastguard Worker
4078*d57664e9SAndroid Build Coastguard Worker //printf("Copying back in %d non-public configs, have %d\n", N, origOrder.size());
4079*d57664e9SAndroid Build Coastguard Worker
4080*d57664e9SAndroid Build Coastguard Worker if (N != origOrder.size()) {
4081*d57664e9SAndroid Build Coastguard Worker printf("Internal error: remaining private symbol count mismatch\n");
4082*d57664e9SAndroid Build Coastguard Worker N = origOrder.size();
4083*d57664e9SAndroid Build Coastguard Worker }
4084*d57664e9SAndroid Build Coastguard Worker
4085*d57664e9SAndroid Build Coastguard Worker j = 0;
4086*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4087*d57664e9SAndroid Build Coastguard Worker const sp<ConfigList>& e = origOrder.itemAt(i);
4088*d57664e9SAndroid Build Coastguard Worker // There will always be enough room for the remaining entries.
4089*d57664e9SAndroid Build Coastguard Worker while (mOrderedConfigs.itemAt(j) != NULL) {
4090*d57664e9SAndroid Build Coastguard Worker j++;
4091*d57664e9SAndroid Build Coastguard Worker }
4092*d57664e9SAndroid Build Coastguard Worker mOrderedConfigs.replaceAt(e, j);
4093*d57664e9SAndroid Build Coastguard Worker j++;
4094*d57664e9SAndroid Build Coastguard Worker }
4095*d57664e9SAndroid Build Coastguard Worker
4096*d57664e9SAndroid Build Coastguard Worker return hasError ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
4097*d57664e9SAndroid Build Coastguard Worker }
4098*d57664e9SAndroid Build Coastguard Worker
Package(const String16 & name,size_t packageId)4099*d57664e9SAndroid Build Coastguard Worker ResourceTable::Package::Package(const String16& name, size_t packageId)
4100*d57664e9SAndroid Build Coastguard Worker : mName(name), mPackageId(packageId),
4101*d57664e9SAndroid Build Coastguard Worker mTypeStringsMapping(0xffffffff),
4102*d57664e9SAndroid Build Coastguard Worker mKeyStringsMapping(0xffffffff)
4103*d57664e9SAndroid Build Coastguard Worker {
4104*d57664e9SAndroid Build Coastguard Worker }
4105*d57664e9SAndroid Build Coastguard Worker
getType(const String16 & type,const SourcePos & sourcePos,bool doSetIndex)4106*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::Type> ResourceTable::Package::getType(const String16& type,
4107*d57664e9SAndroid Build Coastguard Worker const SourcePos& sourcePos,
4108*d57664e9SAndroid Build Coastguard Worker bool doSetIndex)
4109*d57664e9SAndroid Build Coastguard Worker {
4110*d57664e9SAndroid Build Coastguard Worker sp<Type> t = mTypes.valueFor(type);
4111*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
4112*d57664e9SAndroid Build Coastguard Worker t = new Type(type, sourcePos);
4113*d57664e9SAndroid Build Coastguard Worker mTypes.add(type, t);
4114*d57664e9SAndroid Build Coastguard Worker mOrderedTypes.add(t);
4115*d57664e9SAndroid Build Coastguard Worker if (doSetIndex) {
4116*d57664e9SAndroid Build Coastguard Worker // For some reason the type's index is set to one plus the index
4117*d57664e9SAndroid Build Coastguard Worker // in the mOrderedTypes list, rather than just the index.
4118*d57664e9SAndroid Build Coastguard Worker t->setIndex(mOrderedTypes.size());
4119*d57664e9SAndroid Build Coastguard Worker }
4120*d57664e9SAndroid Build Coastguard Worker }
4121*d57664e9SAndroid Build Coastguard Worker return t;
4122*d57664e9SAndroid Build Coastguard Worker }
4123*d57664e9SAndroid Build Coastguard Worker
setTypeStrings(const sp<AaptFile> & data)4124*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Package::setTypeStrings(const sp<AaptFile>& data)
4125*d57664e9SAndroid Build Coastguard Worker {
4126*d57664e9SAndroid Build Coastguard Worker status_t err = setStrings(data, &mTypeStrings, &mTypeStringsMapping);
4127*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
4128*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: Type string data is corrupt!\n");
4129*d57664e9SAndroid Build Coastguard Worker return err;
4130*d57664e9SAndroid Build Coastguard Worker }
4131*d57664e9SAndroid Build Coastguard Worker
4132*d57664e9SAndroid Build Coastguard Worker // Retain a reference to the new data after we've successfully replaced
4133*d57664e9SAndroid Build Coastguard Worker // all uses of the old reference (in setStrings() ).
4134*d57664e9SAndroid Build Coastguard Worker mTypeStringsData = data;
4135*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4136*d57664e9SAndroid Build Coastguard Worker }
4137*d57664e9SAndroid Build Coastguard Worker
setKeyStrings(const sp<AaptFile> & data)4138*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Package::setKeyStrings(const sp<AaptFile>& data)
4139*d57664e9SAndroid Build Coastguard Worker {
4140*d57664e9SAndroid Build Coastguard Worker status_t err = setStrings(data, &mKeyStrings, &mKeyStringsMapping);
4141*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
4142*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "ERROR: Key string data is corrupt!\n");
4143*d57664e9SAndroid Build Coastguard Worker return err;
4144*d57664e9SAndroid Build Coastguard Worker }
4145*d57664e9SAndroid Build Coastguard Worker
4146*d57664e9SAndroid Build Coastguard Worker // Retain a reference to the new data after we've successfully replaced
4147*d57664e9SAndroid Build Coastguard Worker // all uses of the old reference (in setStrings() ).
4148*d57664e9SAndroid Build Coastguard Worker mKeyStringsData = data;
4149*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4150*d57664e9SAndroid Build Coastguard Worker }
4151*d57664e9SAndroid Build Coastguard Worker
setStrings(const sp<AaptFile> & data,ResStringPool * strings,DefaultKeyedVector<String16,uint32_t> * mappings)4152*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Package::setStrings(const sp<AaptFile>& data,
4153*d57664e9SAndroid Build Coastguard Worker ResStringPool* strings,
4154*d57664e9SAndroid Build Coastguard Worker DefaultKeyedVector<String16, uint32_t>* mappings)
4155*d57664e9SAndroid Build Coastguard Worker {
4156*d57664e9SAndroid Build Coastguard Worker if (data->getData() == NULL) {
4157*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
4158*d57664e9SAndroid Build Coastguard Worker }
4159*d57664e9SAndroid Build Coastguard Worker
4160*d57664e9SAndroid Build Coastguard Worker status_t err = strings->setTo(data->getData(), data->getSize());
4161*d57664e9SAndroid Build Coastguard Worker if (err == NO_ERROR) {
4162*d57664e9SAndroid Build Coastguard Worker const size_t N = strings->size();
4163*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
4164*d57664e9SAndroid Build Coastguard Worker size_t len;
4165*d57664e9SAndroid Build Coastguard Worker mappings->add(String16(UnpackOptionalString(strings->stringAt(i), &len)), i);
4166*d57664e9SAndroid Build Coastguard Worker }
4167*d57664e9SAndroid Build Coastguard Worker }
4168*d57664e9SAndroid Build Coastguard Worker return err;
4169*d57664e9SAndroid Build Coastguard Worker }
4170*d57664e9SAndroid Build Coastguard Worker
applyPublicTypeOrder()4171*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::Package::applyPublicTypeOrder()
4172*d57664e9SAndroid Build Coastguard Worker {
4173*d57664e9SAndroid Build Coastguard Worker size_t N = mOrderedTypes.size();
4174*d57664e9SAndroid Build Coastguard Worker Vector<sp<Type> > origOrder(mOrderedTypes);
4175*d57664e9SAndroid Build Coastguard Worker
4176*d57664e9SAndroid Build Coastguard Worker size_t i;
4177*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4178*d57664e9SAndroid Build Coastguard Worker mOrderedTypes.replaceAt(NULL, i);
4179*d57664e9SAndroid Build Coastguard Worker }
4180*d57664e9SAndroid Build Coastguard Worker
4181*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4182*d57664e9SAndroid Build Coastguard Worker sp<Type> t = origOrder.itemAt(i);
4183*d57664e9SAndroid Build Coastguard Worker int32_t idx = t->getPublicIndex();
4184*d57664e9SAndroid Build Coastguard Worker if (idx > 0) {
4185*d57664e9SAndroid Build Coastguard Worker idx--;
4186*d57664e9SAndroid Build Coastguard Worker while (idx >= (int32_t)mOrderedTypes.size()) {
4187*d57664e9SAndroid Build Coastguard Worker mOrderedTypes.add();
4188*d57664e9SAndroid Build Coastguard Worker }
4189*d57664e9SAndroid Build Coastguard Worker if (mOrderedTypes.itemAt(idx) != NULL) {
4190*d57664e9SAndroid Build Coastguard Worker sp<Type> ot = mOrderedTypes.itemAt(idx);
4191*d57664e9SAndroid Build Coastguard Worker t->getFirstPublicSourcePos().error("Multiple type names declared for public type"
4192*d57664e9SAndroid Build Coastguard Worker " identifier 0x%x (%s vs %s).\n"
4193*d57664e9SAndroid Build Coastguard Worker "%s:%d: Originally defined here.",
4194*d57664e9SAndroid Build Coastguard Worker idx, String8(ot->getName()).c_str(),
4195*d57664e9SAndroid Build Coastguard Worker String8(t->getName()).c_str(),
4196*d57664e9SAndroid Build Coastguard Worker ot->getFirstPublicSourcePos().file.c_str(),
4197*d57664e9SAndroid Build Coastguard Worker ot->getFirstPublicSourcePos().line);
4198*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
4199*d57664e9SAndroid Build Coastguard Worker }
4200*d57664e9SAndroid Build Coastguard Worker mOrderedTypes.replaceAt(t, idx);
4201*d57664e9SAndroid Build Coastguard Worker origOrder.removeAt(i);
4202*d57664e9SAndroid Build Coastguard Worker i--;
4203*d57664e9SAndroid Build Coastguard Worker N--;
4204*d57664e9SAndroid Build Coastguard Worker }
4205*d57664e9SAndroid Build Coastguard Worker }
4206*d57664e9SAndroid Build Coastguard Worker
4207*d57664e9SAndroid Build Coastguard Worker size_t j=0;
4208*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4209*d57664e9SAndroid Build Coastguard Worker const sp<Type>& t = origOrder.itemAt(i);
4210*d57664e9SAndroid Build Coastguard Worker // There will always be enough room for the remaining types.
4211*d57664e9SAndroid Build Coastguard Worker while (mOrderedTypes.itemAt(j) != NULL) {
4212*d57664e9SAndroid Build Coastguard Worker j++;
4213*d57664e9SAndroid Build Coastguard Worker }
4214*d57664e9SAndroid Build Coastguard Worker mOrderedTypes.replaceAt(t, j);
4215*d57664e9SAndroid Build Coastguard Worker }
4216*d57664e9SAndroid Build Coastguard Worker
4217*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4218*d57664e9SAndroid Build Coastguard Worker }
4219*d57664e9SAndroid Build Coastguard Worker
movePrivateAttrs()4220*d57664e9SAndroid Build Coastguard Worker void ResourceTable::Package::movePrivateAttrs() {
4221*d57664e9SAndroid Build Coastguard Worker sp<Type> attr = mTypes.valueFor(String16("attr"));
4222*d57664e9SAndroid Build Coastguard Worker if (attr == NULL) {
4223*d57664e9SAndroid Build Coastguard Worker // Nothing to do.
4224*d57664e9SAndroid Build Coastguard Worker return;
4225*d57664e9SAndroid Build Coastguard Worker }
4226*d57664e9SAndroid Build Coastguard Worker
4227*d57664e9SAndroid Build Coastguard Worker Vector<sp<ConfigList> > privateAttrs;
4228*d57664e9SAndroid Build Coastguard Worker
4229*d57664e9SAndroid Build Coastguard Worker bool hasPublic = false;
4230*d57664e9SAndroid Build Coastguard Worker const Vector<sp<ConfigList> >& configs = attr->getOrderedConfigs();
4231*d57664e9SAndroid Build Coastguard Worker const size_t configCount = configs.size();
4232*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < configCount; i++) {
4233*d57664e9SAndroid Build Coastguard Worker if (configs[i] == NULL) {
4234*d57664e9SAndroid Build Coastguard Worker continue;
4235*d57664e9SAndroid Build Coastguard Worker }
4236*d57664e9SAndroid Build Coastguard Worker
4237*d57664e9SAndroid Build Coastguard Worker if (attr->isPublic(configs[i]->getName())) {
4238*d57664e9SAndroid Build Coastguard Worker hasPublic = true;
4239*d57664e9SAndroid Build Coastguard Worker } else {
4240*d57664e9SAndroid Build Coastguard Worker privateAttrs.add(configs[i]);
4241*d57664e9SAndroid Build Coastguard Worker }
4242*d57664e9SAndroid Build Coastguard Worker }
4243*d57664e9SAndroid Build Coastguard Worker
4244*d57664e9SAndroid Build Coastguard Worker // Only if we have public attributes do we create a separate type for
4245*d57664e9SAndroid Build Coastguard Worker // private attributes.
4246*d57664e9SAndroid Build Coastguard Worker if (!hasPublic) {
4247*d57664e9SAndroid Build Coastguard Worker return;
4248*d57664e9SAndroid Build Coastguard Worker }
4249*d57664e9SAndroid Build Coastguard Worker
4250*d57664e9SAndroid Build Coastguard Worker // Create a new type for private attributes.
4251*d57664e9SAndroid Build Coastguard Worker sp<Type> privateAttrType = getType(String16(kAttrPrivateType), SourcePos());
4252*d57664e9SAndroid Build Coastguard Worker
4253*d57664e9SAndroid Build Coastguard Worker const size_t privateAttrCount = privateAttrs.size();
4254*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < privateAttrCount; i++) {
4255*d57664e9SAndroid Build Coastguard Worker const sp<ConfigList>& cl = privateAttrs[i];
4256*d57664e9SAndroid Build Coastguard Worker
4257*d57664e9SAndroid Build Coastguard Worker // Remove the private attributes from their current type.
4258*d57664e9SAndroid Build Coastguard Worker attr->removeEntry(cl->getName());
4259*d57664e9SAndroid Build Coastguard Worker
4260*d57664e9SAndroid Build Coastguard Worker // Add it to the new type.
4261*d57664e9SAndroid Build Coastguard Worker const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries = cl->getEntries();
4262*d57664e9SAndroid Build Coastguard Worker const size_t entryCount = entries.size();
4263*d57664e9SAndroid Build Coastguard Worker for (size_t j = 0; j < entryCount; j++) {
4264*d57664e9SAndroid Build Coastguard Worker const sp<Entry>& oldEntry = entries[j];
4265*d57664e9SAndroid Build Coastguard Worker sp<Entry> entry = privateAttrType->getEntry(
4266*d57664e9SAndroid Build Coastguard Worker cl->getName(), oldEntry->getPos(), &entries.keyAt(j));
4267*d57664e9SAndroid Build Coastguard Worker *entry = *oldEntry;
4268*d57664e9SAndroid Build Coastguard Worker }
4269*d57664e9SAndroid Build Coastguard Worker
4270*d57664e9SAndroid Build Coastguard Worker // Move the symbols to the new type.
4271*d57664e9SAndroid Build Coastguard Worker
4272*d57664e9SAndroid Build Coastguard Worker }
4273*d57664e9SAndroid Build Coastguard Worker }
4274*d57664e9SAndroid Build Coastguard Worker
getPackage(const String16 & package)4275*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
4276*d57664e9SAndroid Build Coastguard Worker {
4277*d57664e9SAndroid Build Coastguard Worker if (package != mAssetsPackage) {
4278*d57664e9SAndroid Build Coastguard Worker return NULL;
4279*d57664e9SAndroid Build Coastguard Worker }
4280*d57664e9SAndroid Build Coastguard Worker return mPackages.valueFor(package);
4281*d57664e9SAndroid Build Coastguard Worker }
4282*d57664e9SAndroid Build Coastguard Worker
getType(const String16 & package,const String16 & type,const SourcePos & sourcePos,bool doSetIndex)4283*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::Type> ResourceTable::getType(const String16& package,
4284*d57664e9SAndroid Build Coastguard Worker const String16& type,
4285*d57664e9SAndroid Build Coastguard Worker const SourcePos& sourcePos,
4286*d57664e9SAndroid Build Coastguard Worker bool doSetIndex)
4287*d57664e9SAndroid Build Coastguard Worker {
4288*d57664e9SAndroid Build Coastguard Worker sp<Package> p = getPackage(package);
4289*d57664e9SAndroid Build Coastguard Worker if (p == NULL) {
4290*d57664e9SAndroid Build Coastguard Worker return NULL;
4291*d57664e9SAndroid Build Coastguard Worker }
4292*d57664e9SAndroid Build Coastguard Worker return p->getType(type, sourcePos, doSetIndex);
4293*d57664e9SAndroid Build Coastguard Worker }
4294*d57664e9SAndroid Build Coastguard Worker
getEntry(const String16 & package,const String16 & type,const String16 & name,const SourcePos & sourcePos,bool overlay,const ResTable_config * config,bool doSetIndex)4295*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::Entry> ResourceTable::getEntry(const String16& package,
4296*d57664e9SAndroid Build Coastguard Worker const String16& type,
4297*d57664e9SAndroid Build Coastguard Worker const String16& name,
4298*d57664e9SAndroid Build Coastguard Worker const SourcePos& sourcePos,
4299*d57664e9SAndroid Build Coastguard Worker bool overlay,
4300*d57664e9SAndroid Build Coastguard Worker const ResTable_config* config,
4301*d57664e9SAndroid Build Coastguard Worker bool doSetIndex)
4302*d57664e9SAndroid Build Coastguard Worker {
4303*d57664e9SAndroid Build Coastguard Worker sp<Type> t = getType(package, type, sourcePos, doSetIndex);
4304*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
4305*d57664e9SAndroid Build Coastguard Worker return NULL;
4306*d57664e9SAndroid Build Coastguard Worker }
4307*d57664e9SAndroid Build Coastguard Worker return t->getEntry(name, sourcePos, config, doSetIndex, overlay, mBundle->getAutoAddOverlay());
4308*d57664e9SAndroid Build Coastguard Worker }
4309*d57664e9SAndroid Build Coastguard Worker
getConfigList(const String16 & package,const String16 & type,const String16 & name) const4310*d57664e9SAndroid Build Coastguard Worker sp<ResourceTable::ConfigList> ResourceTable::getConfigList(const String16& package,
4311*d57664e9SAndroid Build Coastguard Worker const String16& type, const String16& name) const
4312*d57664e9SAndroid Build Coastguard Worker {
4313*d57664e9SAndroid Build Coastguard Worker const size_t packageCount = mOrderedPackages.size();
4314*d57664e9SAndroid Build Coastguard Worker for (size_t pi = 0; pi < packageCount; pi++) {
4315*d57664e9SAndroid Build Coastguard Worker const sp<Package>& p = mOrderedPackages[pi];
4316*d57664e9SAndroid Build Coastguard Worker if (p == NULL || p->getName() != package) {
4317*d57664e9SAndroid Build Coastguard Worker continue;
4318*d57664e9SAndroid Build Coastguard Worker }
4319*d57664e9SAndroid Build Coastguard Worker
4320*d57664e9SAndroid Build Coastguard Worker const Vector<sp<Type> >& types = p->getOrderedTypes();
4321*d57664e9SAndroid Build Coastguard Worker const size_t typeCount = types.size();
4322*d57664e9SAndroid Build Coastguard Worker for (size_t ti = 0; ti < typeCount; ti++) {
4323*d57664e9SAndroid Build Coastguard Worker const sp<Type>& t = types[ti];
4324*d57664e9SAndroid Build Coastguard Worker if (t == NULL || t->getName() != type) {
4325*d57664e9SAndroid Build Coastguard Worker continue;
4326*d57664e9SAndroid Build Coastguard Worker }
4327*d57664e9SAndroid Build Coastguard Worker
4328*d57664e9SAndroid Build Coastguard Worker const Vector<sp<ConfigList> >& configs = t->getOrderedConfigs();
4329*d57664e9SAndroid Build Coastguard Worker const size_t configCount = configs.size();
4330*d57664e9SAndroid Build Coastguard Worker for (size_t ci = 0; ci < configCount; ci++) {
4331*d57664e9SAndroid Build Coastguard Worker const sp<ConfigList>& cl = configs[ci];
4332*d57664e9SAndroid Build Coastguard Worker if (cl == NULL || cl->getName() != name) {
4333*d57664e9SAndroid Build Coastguard Worker continue;
4334*d57664e9SAndroid Build Coastguard Worker }
4335*d57664e9SAndroid Build Coastguard Worker
4336*d57664e9SAndroid Build Coastguard Worker return cl;
4337*d57664e9SAndroid Build Coastguard Worker }
4338*d57664e9SAndroid Build Coastguard Worker }
4339*d57664e9SAndroid Build Coastguard Worker }
4340*d57664e9SAndroid Build Coastguard Worker return NULL;
4341*d57664e9SAndroid Build Coastguard Worker }
4342*d57664e9SAndroid Build Coastguard Worker
getEntry(uint32_t resID,const ResTable_config * config) const4343*d57664e9SAndroid Build Coastguard Worker sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
4344*d57664e9SAndroid Build Coastguard Worker const ResTable_config* config) const
4345*d57664e9SAndroid Build Coastguard Worker {
4346*d57664e9SAndroid Build Coastguard Worker size_t pid = Res_GETPACKAGE(resID)+1;
4347*d57664e9SAndroid Build Coastguard Worker const size_t N = mOrderedPackages.size();
4348*d57664e9SAndroid Build Coastguard Worker sp<Package> p;
4349*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < N; i++) {
4350*d57664e9SAndroid Build Coastguard Worker sp<Package> check = mOrderedPackages[i];
4351*d57664e9SAndroid Build Coastguard Worker if (check->getAssignedId() == pid) {
4352*d57664e9SAndroid Build Coastguard Worker p = check;
4353*d57664e9SAndroid Build Coastguard Worker break;
4354*d57664e9SAndroid Build Coastguard Worker }
4355*d57664e9SAndroid Build Coastguard Worker
4356*d57664e9SAndroid Build Coastguard Worker }
4357*d57664e9SAndroid Build Coastguard Worker if (p == NULL) {
4358*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: Package not found for resource #%08x\n", resID);
4359*d57664e9SAndroid Build Coastguard Worker return NULL;
4360*d57664e9SAndroid Build Coastguard Worker }
4361*d57664e9SAndroid Build Coastguard Worker
4362*d57664e9SAndroid Build Coastguard Worker int tid = Res_GETTYPE(resID);
4363*d57664e9SAndroid Build Coastguard Worker if (tid < 0 || tid >= (int)p->getOrderedTypes().size()) {
4364*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: Type not found for resource #%08x\n", resID);
4365*d57664e9SAndroid Build Coastguard Worker return NULL;
4366*d57664e9SAndroid Build Coastguard Worker }
4367*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes()[tid];
4368*d57664e9SAndroid Build Coastguard Worker
4369*d57664e9SAndroid Build Coastguard Worker int eid = Res_GETENTRY(resID);
4370*d57664e9SAndroid Build Coastguard Worker if (eid < 0 || eid >= (int)t->getOrderedConfigs().size()) {
4371*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
4372*d57664e9SAndroid Build Coastguard Worker return NULL;
4373*d57664e9SAndroid Build Coastguard Worker }
4374*d57664e9SAndroid Build Coastguard Worker
4375*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs()[eid];
4376*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
4377*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
4378*d57664e9SAndroid Build Coastguard Worker return NULL;
4379*d57664e9SAndroid Build Coastguard Worker }
4380*d57664e9SAndroid Build Coastguard Worker
4381*d57664e9SAndroid Build Coastguard Worker ConfigDescription cdesc;
4382*d57664e9SAndroid Build Coastguard Worker if (config) cdesc = *config;
4383*d57664e9SAndroid Build Coastguard Worker sp<Entry> e = c->getEntries().valueFor(cdesc);
4384*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
4385*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: Entry configuration not found for resource #%08x\n", resID);
4386*d57664e9SAndroid Build Coastguard Worker return NULL;
4387*d57664e9SAndroid Build Coastguard Worker }
4388*d57664e9SAndroid Build Coastguard Worker
4389*d57664e9SAndroid Build Coastguard Worker return e;
4390*d57664e9SAndroid Build Coastguard Worker }
4391*d57664e9SAndroid Build Coastguard Worker
getItem(uint32_t resID,uint32_t attrID) const4392*d57664e9SAndroid Build Coastguard Worker const ResourceTable::Item* ResourceTable::getItem(uint32_t resID, uint32_t attrID) const
4393*d57664e9SAndroid Build Coastguard Worker {
4394*d57664e9SAndroid Build Coastguard Worker sp<const Entry> e = getEntry(resID);
4395*d57664e9SAndroid Build Coastguard Worker if (e == NULL) {
4396*d57664e9SAndroid Build Coastguard Worker return NULL;
4397*d57664e9SAndroid Build Coastguard Worker }
4398*d57664e9SAndroid Build Coastguard Worker
4399*d57664e9SAndroid Build Coastguard Worker const size_t N = e->getBag().size();
4400*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
4401*d57664e9SAndroid Build Coastguard Worker const Item& it = e->getBag().valueAt(i);
4402*d57664e9SAndroid Build Coastguard Worker if (it.bagKeyId == 0) {
4403*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n",
4404*d57664e9SAndroid Build Coastguard Worker String8(e->getName()).c_str(),
4405*d57664e9SAndroid Build Coastguard Worker String8(e->getBag().keyAt(i)).c_str());
4406*d57664e9SAndroid Build Coastguard Worker }
4407*d57664e9SAndroid Build Coastguard Worker if (it.bagKeyId == attrID) {
4408*d57664e9SAndroid Build Coastguard Worker return ⁢
4409*d57664e9SAndroid Build Coastguard Worker }
4410*d57664e9SAndroid Build Coastguard Worker }
4411*d57664e9SAndroid Build Coastguard Worker
4412*d57664e9SAndroid Build Coastguard Worker return NULL;
4413*d57664e9SAndroid Build Coastguard Worker }
4414*d57664e9SAndroid Build Coastguard Worker
getItemValue(uint32_t resID,uint32_t attrID,Res_value * outValue)4415*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::getItemValue(
4416*d57664e9SAndroid Build Coastguard Worker uint32_t resID, uint32_t attrID, Res_value* outValue)
4417*d57664e9SAndroid Build Coastguard Worker {
4418*d57664e9SAndroid Build Coastguard Worker const Item* item = getItem(resID, attrID);
4419*d57664e9SAndroid Build Coastguard Worker
4420*d57664e9SAndroid Build Coastguard Worker bool res = false;
4421*d57664e9SAndroid Build Coastguard Worker if (item != NULL) {
4422*d57664e9SAndroid Build Coastguard Worker if (item->evaluating) {
4423*d57664e9SAndroid Build Coastguard Worker sp<const Entry> e = getEntry(resID);
4424*d57664e9SAndroid Build Coastguard Worker const size_t N = e->getBag().size();
4425*d57664e9SAndroid Build Coastguard Worker size_t i;
4426*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
4427*d57664e9SAndroid Build Coastguard Worker if (&e->getBag().valueAt(i) == item) {
4428*d57664e9SAndroid Build Coastguard Worker break;
4429*d57664e9SAndroid Build Coastguard Worker }
4430*d57664e9SAndroid Build Coastguard Worker }
4431*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n",
4432*d57664e9SAndroid Build Coastguard Worker String8(e->getName()).c_str(),
4433*d57664e9SAndroid Build Coastguard Worker String8(e->getBag().keyAt(i)).c_str());
4434*d57664e9SAndroid Build Coastguard Worker return false;
4435*d57664e9SAndroid Build Coastguard Worker }
4436*d57664e9SAndroid Build Coastguard Worker item->evaluating = true;
4437*d57664e9SAndroid Build Coastguard Worker res = stringToValue(outValue, NULL, item->value, false, false, item->bagKeyId);
4438*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
4439*d57664e9SAndroid Build Coastguard Worker if (res) {
4440*d57664e9SAndroid Build Coastguard Worker printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n",
4441*d57664e9SAndroid Build Coastguard Worker resID, attrID, String8(getEntry(resID)->getName()).c_str(),
4442*d57664e9SAndroid Build Coastguard Worker outValue->dataType, outValue->data);
4443*d57664e9SAndroid Build Coastguard Worker } else {
4444*d57664e9SAndroid Build Coastguard Worker printf("getItemValue of #%08x[#%08x]: failed\n",
4445*d57664e9SAndroid Build Coastguard Worker resID, attrID);
4446*d57664e9SAndroid Build Coastguard Worker }
4447*d57664e9SAndroid Build Coastguard Worker }
4448*d57664e9SAndroid Build Coastguard Worker item->evaluating = false;
4449*d57664e9SAndroid Build Coastguard Worker }
4450*d57664e9SAndroid Build Coastguard Worker return res;
4451*d57664e9SAndroid Build Coastguard Worker }
4452*d57664e9SAndroid Build Coastguard Worker
4453*d57664e9SAndroid Build Coastguard Worker /**
4454*d57664e9SAndroid Build Coastguard Worker * Returns the SDK version at which the attribute was
4455*d57664e9SAndroid Build Coastguard Worker * made public, or -1 if the resource ID is not an attribute
4456*d57664e9SAndroid Build Coastguard Worker * or is not public.
4457*d57664e9SAndroid Build Coastguard Worker */
getPublicAttributeSdkLevel(uint32_t attrId) const4458*d57664e9SAndroid Build Coastguard Worker int ResourceTable::getPublicAttributeSdkLevel(uint32_t attrId) const {
4459*d57664e9SAndroid Build Coastguard Worker if (Res_GETPACKAGE(attrId) + 1 != 0x01 || Res_GETTYPE(attrId) + 1 != 0x01) {
4460*d57664e9SAndroid Build Coastguard Worker return -1;
4461*d57664e9SAndroid Build Coastguard Worker }
4462*d57664e9SAndroid Build Coastguard Worker
4463*d57664e9SAndroid Build Coastguard Worker uint32_t specFlags;
4464*d57664e9SAndroid Build Coastguard Worker if (!mAssets->getIncludedResources().getResourceFlags(attrId, &specFlags)) {
4465*d57664e9SAndroid Build Coastguard Worker return -1;
4466*d57664e9SAndroid Build Coastguard Worker }
4467*d57664e9SAndroid Build Coastguard Worker
4468*d57664e9SAndroid Build Coastguard Worker if ((specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
4469*d57664e9SAndroid Build Coastguard Worker return -1;
4470*d57664e9SAndroid Build Coastguard Worker }
4471*d57664e9SAndroid Build Coastguard Worker
4472*d57664e9SAndroid Build Coastguard Worker const size_t entryId = Res_GETENTRY(attrId);
4473*d57664e9SAndroid Build Coastguard Worker if (entryId <= 0x021c) {
4474*d57664e9SAndroid Build Coastguard Worker return 1;
4475*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x021d) {
4476*d57664e9SAndroid Build Coastguard Worker return 2;
4477*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x0269) {
4478*d57664e9SAndroid Build Coastguard Worker return SDK_CUPCAKE;
4479*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x028d) {
4480*d57664e9SAndroid Build Coastguard Worker return SDK_DONUT;
4481*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x02ad) {
4482*d57664e9SAndroid Build Coastguard Worker return SDK_ECLAIR;
4483*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x02b3) {
4484*d57664e9SAndroid Build Coastguard Worker return SDK_ECLAIR_0_1;
4485*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x02b5) {
4486*d57664e9SAndroid Build Coastguard Worker return SDK_ECLAIR_MR1;
4487*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x02bd) {
4488*d57664e9SAndroid Build Coastguard Worker return SDK_FROYO;
4489*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x02cb) {
4490*d57664e9SAndroid Build Coastguard Worker return SDK_GINGERBREAD;
4491*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x0361) {
4492*d57664e9SAndroid Build Coastguard Worker return SDK_HONEYCOMB;
4493*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x0366) {
4494*d57664e9SAndroid Build Coastguard Worker return SDK_HONEYCOMB_MR1;
4495*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x03a6) {
4496*d57664e9SAndroid Build Coastguard Worker return SDK_HONEYCOMB_MR2;
4497*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x03ae) {
4498*d57664e9SAndroid Build Coastguard Worker return SDK_JELLY_BEAN;
4499*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x03cc) {
4500*d57664e9SAndroid Build Coastguard Worker return SDK_JELLY_BEAN_MR1;
4501*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x03da) {
4502*d57664e9SAndroid Build Coastguard Worker return SDK_JELLY_BEAN_MR2;
4503*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x03f1) {
4504*d57664e9SAndroid Build Coastguard Worker return SDK_KITKAT;
4505*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x03f6) {
4506*d57664e9SAndroid Build Coastguard Worker return SDK_KITKAT_WATCH;
4507*d57664e9SAndroid Build Coastguard Worker } else if (entryId <= 0x04ce) {
4508*d57664e9SAndroid Build Coastguard Worker return SDK_LOLLIPOP;
4509*d57664e9SAndroid Build Coastguard Worker } else {
4510*d57664e9SAndroid Build Coastguard Worker // Anything else is marked as defined in
4511*d57664e9SAndroid Build Coastguard Worker // SDK_LOLLIPOP_MR1 since after this
4512*d57664e9SAndroid Build Coastguard Worker // version no attribute compat work
4513*d57664e9SAndroid Build Coastguard Worker // needs to be done.
4514*d57664e9SAndroid Build Coastguard Worker return SDK_LOLLIPOP_MR1;
4515*d57664e9SAndroid Build Coastguard Worker }
4516*d57664e9SAndroid Build Coastguard Worker }
4517*d57664e9SAndroid Build Coastguard Worker
4518*d57664e9SAndroid Build Coastguard Worker /**
4519*d57664e9SAndroid Build Coastguard Worker * First check the Manifest, then check the command line flag.
4520*d57664e9SAndroid Build Coastguard Worker */
getMinSdkVersion(const Bundle * bundle)4521*d57664e9SAndroid Build Coastguard Worker static int getMinSdkVersion(const Bundle* bundle) {
4522*d57664e9SAndroid Build Coastguard Worker if (bundle->getManifestMinSdkVersion() != NULL && strlen(bundle->getManifestMinSdkVersion()) > 0) {
4523*d57664e9SAndroid Build Coastguard Worker return atoi(bundle->getManifestMinSdkVersion());
4524*d57664e9SAndroid Build Coastguard Worker } else if (bundle->getMinSdkVersion() != NULL && strlen(bundle->getMinSdkVersion()) > 0) {
4525*d57664e9SAndroid Build Coastguard Worker return atoi(bundle->getMinSdkVersion());
4526*d57664e9SAndroid Build Coastguard Worker }
4527*d57664e9SAndroid Build Coastguard Worker return 0;
4528*d57664e9SAndroid Build Coastguard Worker }
4529*d57664e9SAndroid Build Coastguard Worker
shouldGenerateVersionedResource(const sp<ResourceTable::ConfigList> & configList,const ConfigDescription & sourceConfig,const int sdkVersionToGenerate)4530*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::shouldGenerateVersionedResource(
4531*d57664e9SAndroid Build Coastguard Worker const sp<ResourceTable::ConfigList>& configList,
4532*d57664e9SAndroid Build Coastguard Worker const ConfigDescription& sourceConfig,
4533*d57664e9SAndroid Build Coastguard Worker const int sdkVersionToGenerate) {
4534*d57664e9SAndroid Build Coastguard Worker assert(sdkVersionToGenerate > sourceConfig.sdkVersion);
4535*d57664e9SAndroid Build Coastguard Worker assert(configList != NULL);
4536*d57664e9SAndroid Build Coastguard Worker const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& entries
4537*d57664e9SAndroid Build Coastguard Worker = configList->getEntries();
4538*d57664e9SAndroid Build Coastguard Worker ssize_t idx = entries.indexOfKey(sourceConfig);
4539*d57664e9SAndroid Build Coastguard Worker
4540*d57664e9SAndroid Build Coastguard Worker // The source config came from this list, so it should be here.
4541*d57664e9SAndroid Build Coastguard Worker assert(idx >= 0);
4542*d57664e9SAndroid Build Coastguard Worker
4543*d57664e9SAndroid Build Coastguard Worker // The next configuration either only varies in sdkVersion, or it is completely different
4544*d57664e9SAndroid Build Coastguard Worker // and therefore incompatible. If it is incompatible, we must generate the versioned resource.
4545*d57664e9SAndroid Build Coastguard Worker
4546*d57664e9SAndroid Build Coastguard Worker // NOTE: The ordering of configurations takes sdkVersion as higher precedence than other
4547*d57664e9SAndroid Build Coastguard Worker // qualifiers, so we need to iterate through the entire list to be sure there
4548*d57664e9SAndroid Build Coastguard Worker // are no higher sdk level versions of this resource.
4549*d57664e9SAndroid Build Coastguard Worker ConfigDescription tempConfig(sourceConfig);
4550*d57664e9SAndroid Build Coastguard Worker for (size_t i = static_cast<size_t>(idx) + 1; i < entries.size(); i++) {
4551*d57664e9SAndroid Build Coastguard Worker const ConfigDescription& nextConfig = entries.keyAt(i);
4552*d57664e9SAndroid Build Coastguard Worker tempConfig.sdkVersion = nextConfig.sdkVersion;
4553*d57664e9SAndroid Build Coastguard Worker if (tempConfig == nextConfig) {
4554*d57664e9SAndroid Build Coastguard Worker // The two configs are the same, check the sdk version.
4555*d57664e9SAndroid Build Coastguard Worker return sdkVersionToGenerate < nextConfig.sdkVersion;
4556*d57664e9SAndroid Build Coastguard Worker }
4557*d57664e9SAndroid Build Coastguard Worker }
4558*d57664e9SAndroid Build Coastguard Worker
4559*d57664e9SAndroid Build Coastguard Worker // No match was found, so we should generate the versioned resource.
4560*d57664e9SAndroid Build Coastguard Worker return true;
4561*d57664e9SAndroid Build Coastguard Worker }
4562*d57664e9SAndroid Build Coastguard Worker
4563*d57664e9SAndroid Build Coastguard Worker /**
4564*d57664e9SAndroid Build Coastguard Worker * Modifies the entries in the resource table to account for compatibility
4565*d57664e9SAndroid Build Coastguard Worker * issues with older versions of Android.
4566*d57664e9SAndroid Build Coastguard Worker *
4567*d57664e9SAndroid Build Coastguard Worker * This primarily handles the issue of private/public attribute clashes
4568*d57664e9SAndroid Build Coastguard Worker * in framework resources.
4569*d57664e9SAndroid Build Coastguard Worker *
4570*d57664e9SAndroid Build Coastguard Worker * AAPT has traditionally assigned resource IDs to public attributes,
4571*d57664e9SAndroid Build Coastguard Worker * and then followed those public definitions with private attributes.
4572*d57664e9SAndroid Build Coastguard Worker *
4573*d57664e9SAndroid Build Coastguard Worker * --- PUBLIC ---
4574*d57664e9SAndroid Build Coastguard Worker * | 0x01010234 | attr/color
4575*d57664e9SAndroid Build Coastguard Worker * | 0x01010235 | attr/background
4576*d57664e9SAndroid Build Coastguard Worker *
4577*d57664e9SAndroid Build Coastguard Worker * --- PRIVATE ---
4578*d57664e9SAndroid Build Coastguard Worker * | 0x01010236 | attr/secret
4579*d57664e9SAndroid Build Coastguard Worker * | 0x01010237 | attr/shhh
4580*d57664e9SAndroid Build Coastguard Worker *
4581*d57664e9SAndroid Build Coastguard Worker * Each release, when attributes are added, they take the place of the private
4582*d57664e9SAndroid Build Coastguard Worker * attributes and the private attributes are shifted down again.
4583*d57664e9SAndroid Build Coastguard Worker *
4584*d57664e9SAndroid Build Coastguard Worker * --- PUBLIC ---
4585*d57664e9SAndroid Build Coastguard Worker * | 0x01010234 | attr/color
4586*d57664e9SAndroid Build Coastguard Worker * | 0x01010235 | attr/background
4587*d57664e9SAndroid Build Coastguard Worker * | 0x01010236 | attr/shinyNewAttr
4588*d57664e9SAndroid Build Coastguard Worker * | 0x01010237 | attr/highlyValuedFeature
4589*d57664e9SAndroid Build Coastguard Worker *
4590*d57664e9SAndroid Build Coastguard Worker * --- PRIVATE ---
4591*d57664e9SAndroid Build Coastguard Worker * | 0x01010238 | attr/secret
4592*d57664e9SAndroid Build Coastguard Worker * | 0x01010239 | attr/shhh
4593*d57664e9SAndroid Build Coastguard Worker *
4594*d57664e9SAndroid Build Coastguard Worker * Platform code may look for private attributes set in a theme. If an app
4595*d57664e9SAndroid Build Coastguard Worker * compiled against a newer version of the platform uses a new public
4596*d57664e9SAndroid Build Coastguard Worker * attribute that happens to have the same ID as the private attribute
4597*d57664e9SAndroid Build Coastguard Worker * the older platform is expecting, then the behavior is undefined.
4598*d57664e9SAndroid Build Coastguard Worker *
4599*d57664e9SAndroid Build Coastguard Worker * We get around this by detecting any newly defined attributes (in L),
4600*d57664e9SAndroid Build Coastguard Worker * copy the resource into a -v21 qualified resource, and delete the
4601*d57664e9SAndroid Build Coastguard Worker * attribute from the original resource. This ensures that older platforms
4602*d57664e9SAndroid Build Coastguard Worker * don't see the new attribute, but when running on L+ platforms, the
4603*d57664e9SAndroid Build Coastguard Worker * attribute will be respected.
4604*d57664e9SAndroid Build Coastguard Worker */
modifyForCompat(const Bundle * bundle)4605*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
4606*d57664e9SAndroid Build Coastguard Worker const int minSdk = getMinSdkVersion(bundle);
4607*d57664e9SAndroid Build Coastguard Worker if (minSdk >= SDK_LOLLIPOP_MR1) {
4608*d57664e9SAndroid Build Coastguard Worker // Lollipop MR1 and up handles public attributes differently, no
4609*d57664e9SAndroid Build Coastguard Worker // need to do any compat modifications.
4610*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4611*d57664e9SAndroid Build Coastguard Worker }
4612*d57664e9SAndroid Build Coastguard Worker
4613*d57664e9SAndroid Build Coastguard Worker const String16 attr16("attr");
4614*d57664e9SAndroid Build Coastguard Worker
4615*d57664e9SAndroid Build Coastguard Worker const size_t packageCount = mOrderedPackages.size();
4616*d57664e9SAndroid Build Coastguard Worker for (size_t pi = 0; pi < packageCount; pi++) {
4617*d57664e9SAndroid Build Coastguard Worker sp<Package> p = mOrderedPackages.itemAt(pi);
4618*d57664e9SAndroid Build Coastguard Worker if (p == NULL || p->getTypes().size() == 0) {
4619*d57664e9SAndroid Build Coastguard Worker // Empty, skip!
4620*d57664e9SAndroid Build Coastguard Worker continue;
4621*d57664e9SAndroid Build Coastguard Worker }
4622*d57664e9SAndroid Build Coastguard Worker
4623*d57664e9SAndroid Build Coastguard Worker const size_t typeCount = p->getOrderedTypes().size();
4624*d57664e9SAndroid Build Coastguard Worker for (size_t ti = 0; ti < typeCount; ti++) {
4625*d57664e9SAndroid Build Coastguard Worker sp<Type> t = p->getOrderedTypes().itemAt(ti);
4626*d57664e9SAndroid Build Coastguard Worker if (t == NULL) {
4627*d57664e9SAndroid Build Coastguard Worker continue;
4628*d57664e9SAndroid Build Coastguard Worker }
4629*d57664e9SAndroid Build Coastguard Worker
4630*d57664e9SAndroid Build Coastguard Worker const size_t configCount = t->getOrderedConfigs().size();
4631*d57664e9SAndroid Build Coastguard Worker for (size_t ci = 0; ci < configCount; ci++) {
4632*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
4633*d57664e9SAndroid Build Coastguard Worker if (c == NULL) {
4634*d57664e9SAndroid Build Coastguard Worker continue;
4635*d57664e9SAndroid Build Coastguard Worker }
4636*d57664e9SAndroid Build Coastguard Worker
4637*d57664e9SAndroid Build Coastguard Worker Vector<key_value_pair_t<ConfigDescription, sp<Entry> > > entriesToAdd;
4638*d57664e9SAndroid Build Coastguard Worker const DefaultKeyedVector<ConfigDescription, sp<Entry> >& entries =
4639*d57664e9SAndroid Build Coastguard Worker c->getEntries();
4640*d57664e9SAndroid Build Coastguard Worker const size_t entryCount = entries.size();
4641*d57664e9SAndroid Build Coastguard Worker for (size_t ei = 0; ei < entryCount; ei++) {
4642*d57664e9SAndroid Build Coastguard Worker const sp<Entry>& e = entries.valueAt(ei);
4643*d57664e9SAndroid Build Coastguard Worker if (e == NULL || e->getType() != Entry::TYPE_BAG) {
4644*d57664e9SAndroid Build Coastguard Worker continue;
4645*d57664e9SAndroid Build Coastguard Worker }
4646*d57664e9SAndroid Build Coastguard Worker
4647*d57664e9SAndroid Build Coastguard Worker const ConfigDescription& config = entries.keyAt(ei);
4648*d57664e9SAndroid Build Coastguard Worker if (config.sdkVersion >= SDK_LOLLIPOP_MR1) {
4649*d57664e9SAndroid Build Coastguard Worker continue;
4650*d57664e9SAndroid Build Coastguard Worker }
4651*d57664e9SAndroid Build Coastguard Worker
4652*d57664e9SAndroid Build Coastguard Worker KeyedVector<int, Vector<String16> > attributesToRemove;
4653*d57664e9SAndroid Build Coastguard Worker const KeyedVector<String16, Item>& bag = e->getBag();
4654*d57664e9SAndroid Build Coastguard Worker const size_t bagCount = bag.size();
4655*d57664e9SAndroid Build Coastguard Worker for (size_t bi = 0; bi < bagCount; bi++) {
4656*d57664e9SAndroid Build Coastguard Worker const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
4657*d57664e9SAndroid Build Coastguard Worker const int sdkLevel = getPublicAttributeSdkLevel(attrId);
4658*d57664e9SAndroid Build Coastguard Worker if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
4659*d57664e9SAndroid Build Coastguard Worker AaptUtil::appendValue(attributesToRemove, sdkLevel, bag.keyAt(bi));
4660*d57664e9SAndroid Build Coastguard Worker }
4661*d57664e9SAndroid Build Coastguard Worker }
4662*d57664e9SAndroid Build Coastguard Worker
4663*d57664e9SAndroid Build Coastguard Worker if (attributesToRemove.isEmpty()) {
4664*d57664e9SAndroid Build Coastguard Worker continue;
4665*d57664e9SAndroid Build Coastguard Worker }
4666*d57664e9SAndroid Build Coastguard Worker
4667*d57664e9SAndroid Build Coastguard Worker const size_t sdkCount = attributesToRemove.size();
4668*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < sdkCount; i++) {
4669*d57664e9SAndroid Build Coastguard Worker const int sdkLevel = attributesToRemove.keyAt(i);
4670*d57664e9SAndroid Build Coastguard Worker
4671*d57664e9SAndroid Build Coastguard Worker if (!shouldGenerateVersionedResource(c, config, sdkLevel)) {
4672*d57664e9SAndroid Build Coastguard Worker // There is a style that will override this generated one.
4673*d57664e9SAndroid Build Coastguard Worker continue;
4674*d57664e9SAndroid Build Coastguard Worker }
4675*d57664e9SAndroid Build Coastguard Worker
4676*d57664e9SAndroid Build Coastguard Worker // Duplicate the entry under the same configuration
4677*d57664e9SAndroid Build Coastguard Worker // but with sdkVersion == sdkLevel.
4678*d57664e9SAndroid Build Coastguard Worker ConfigDescription newConfig(config);
4679*d57664e9SAndroid Build Coastguard Worker newConfig.sdkVersion = sdkLevel;
4680*d57664e9SAndroid Build Coastguard Worker
4681*d57664e9SAndroid Build Coastguard Worker sp<Entry> newEntry = new Entry(*e);
4682*d57664e9SAndroid Build Coastguard Worker
4683*d57664e9SAndroid Build Coastguard Worker // Remove all items that have a higher SDK level than
4684*d57664e9SAndroid Build Coastguard Worker // the one we are synthesizing.
4685*d57664e9SAndroid Build Coastguard Worker for (size_t j = 0; j < sdkCount; j++) {
4686*d57664e9SAndroid Build Coastguard Worker if (j == i) {
4687*d57664e9SAndroid Build Coastguard Worker continue;
4688*d57664e9SAndroid Build Coastguard Worker }
4689*d57664e9SAndroid Build Coastguard Worker
4690*d57664e9SAndroid Build Coastguard Worker if (attributesToRemove.keyAt(j) > sdkLevel) {
4691*d57664e9SAndroid Build Coastguard Worker const size_t attrCount = attributesToRemove[j].size();
4692*d57664e9SAndroid Build Coastguard Worker for (size_t k = 0; k < attrCount; k++) {
4693*d57664e9SAndroid Build Coastguard Worker newEntry->removeFromBag(attributesToRemove[j][k]);
4694*d57664e9SAndroid Build Coastguard Worker }
4695*d57664e9SAndroid Build Coastguard Worker }
4696*d57664e9SAndroid Build Coastguard Worker }
4697*d57664e9SAndroid Build Coastguard Worker
4698*d57664e9SAndroid Build Coastguard Worker entriesToAdd.add(key_value_pair_t<ConfigDescription, sp<Entry> >(
4699*d57664e9SAndroid Build Coastguard Worker newConfig, newEntry));
4700*d57664e9SAndroid Build Coastguard Worker }
4701*d57664e9SAndroid Build Coastguard Worker
4702*d57664e9SAndroid Build Coastguard Worker // Remove the attribute from the original.
4703*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < attributesToRemove.size(); i++) {
4704*d57664e9SAndroid Build Coastguard Worker for (size_t j = 0; j < attributesToRemove[i].size(); j++) {
4705*d57664e9SAndroid Build Coastguard Worker e->removeFromBag(attributesToRemove[i][j]);
4706*d57664e9SAndroid Build Coastguard Worker }
4707*d57664e9SAndroid Build Coastguard Worker }
4708*d57664e9SAndroid Build Coastguard Worker }
4709*d57664e9SAndroid Build Coastguard Worker
4710*d57664e9SAndroid Build Coastguard Worker const size_t entriesToAddCount = entriesToAdd.size();
4711*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < entriesToAddCount; i++) {
4712*d57664e9SAndroid Build Coastguard Worker assert(entries.indexOfKey(entriesToAdd[i].key) < 0);
4713*d57664e9SAndroid Build Coastguard Worker
4714*d57664e9SAndroid Build Coastguard Worker if (bundle->getVerbose()) {
4715*d57664e9SAndroid Build Coastguard Worker entriesToAdd[i].value->getPos()
4716*d57664e9SAndroid Build Coastguard Worker .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
4717*d57664e9SAndroid Build Coastguard Worker entriesToAdd[i].key.sdkVersion,
4718*d57664e9SAndroid Build Coastguard Worker String8(p->getName()).c_str(),
4719*d57664e9SAndroid Build Coastguard Worker String8(t->getName()).c_str(),
4720*d57664e9SAndroid Build Coastguard Worker String8(entriesToAdd[i].value->getName()).c_str(),
4721*d57664e9SAndroid Build Coastguard Worker entriesToAdd[i].key.toString().c_str());
4722*d57664e9SAndroid Build Coastguard Worker }
4723*d57664e9SAndroid Build Coastguard Worker
4724*d57664e9SAndroid Build Coastguard Worker sp<Entry> newEntry = t->getEntry(c->getName(),
4725*d57664e9SAndroid Build Coastguard Worker entriesToAdd[i].value->getPos(),
4726*d57664e9SAndroid Build Coastguard Worker &entriesToAdd[i].key);
4727*d57664e9SAndroid Build Coastguard Worker
4728*d57664e9SAndroid Build Coastguard Worker *newEntry = *entriesToAdd[i].value;
4729*d57664e9SAndroid Build Coastguard Worker }
4730*d57664e9SAndroid Build Coastguard Worker }
4731*d57664e9SAndroid Build Coastguard Worker }
4732*d57664e9SAndroid Build Coastguard Worker }
4733*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4734*d57664e9SAndroid Build Coastguard Worker }
4735*d57664e9SAndroid Build Coastguard Worker
4736*d57664e9SAndroid Build Coastguard Worker const String16 kTransitionElements[] = {
4737*d57664e9SAndroid Build Coastguard Worker String16("fade"),
4738*d57664e9SAndroid Build Coastguard Worker String16("changeBounds"),
4739*d57664e9SAndroid Build Coastguard Worker String16("slide"),
4740*d57664e9SAndroid Build Coastguard Worker String16("explode"),
4741*d57664e9SAndroid Build Coastguard Worker String16("changeImageTransform"),
4742*d57664e9SAndroid Build Coastguard Worker String16("changeTransform"),
4743*d57664e9SAndroid Build Coastguard Worker String16("changeClipBounds"),
4744*d57664e9SAndroid Build Coastguard Worker String16("autoTransition"),
4745*d57664e9SAndroid Build Coastguard Worker String16("recolor"),
4746*d57664e9SAndroid Build Coastguard Worker String16("changeScroll"),
4747*d57664e9SAndroid Build Coastguard Worker String16("transitionSet"),
4748*d57664e9SAndroid Build Coastguard Worker String16("transition"),
4749*d57664e9SAndroid Build Coastguard Worker String16("transitionManager"),
4750*d57664e9SAndroid Build Coastguard Worker };
4751*d57664e9SAndroid Build Coastguard Worker
IsTransitionElement(const String16 & name)4752*d57664e9SAndroid Build Coastguard Worker static bool IsTransitionElement(const String16& name) {
4753*d57664e9SAndroid Build Coastguard Worker for (int i = 0, size = sizeof(kTransitionElements) / sizeof(kTransitionElements[0]);
4754*d57664e9SAndroid Build Coastguard Worker i < size; ++i) {
4755*d57664e9SAndroid Build Coastguard Worker if (name == kTransitionElements[i]) {
4756*d57664e9SAndroid Build Coastguard Worker return true;
4757*d57664e9SAndroid Build Coastguard Worker }
4758*d57664e9SAndroid Build Coastguard Worker }
4759*d57664e9SAndroid Build Coastguard Worker return false;
4760*d57664e9SAndroid Build Coastguard Worker }
4761*d57664e9SAndroid Build Coastguard Worker
versionForCompat(const Bundle * bundle,const String16 & resourceName,const sp<AaptFile> & target,const sp<XMLNode> & root)4762*d57664e9SAndroid Build Coastguard Worker bool ResourceTable::versionForCompat(const Bundle* bundle, const String16& resourceName,
4763*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target, const sp<XMLNode>& root) {
4764*d57664e9SAndroid Build Coastguard Worker XMLNode* node = root.get();
4765*d57664e9SAndroid Build Coastguard Worker while (node->getType() != XMLNode::TYPE_ELEMENT) {
4766*d57664e9SAndroid Build Coastguard Worker // We're assuming the root element is what we're looking for, which can only be under a
4767*d57664e9SAndroid Build Coastguard Worker // bunch of namespace declarations.
4768*d57664e9SAndroid Build Coastguard Worker if (node->getChildren().size() != 1) {
4769*d57664e9SAndroid Build Coastguard Worker // Not sure what to do, bail.
4770*d57664e9SAndroid Build Coastguard Worker return false;
4771*d57664e9SAndroid Build Coastguard Worker }
4772*d57664e9SAndroid Build Coastguard Worker node = node->getChildren().itemAt(0).get();
4773*d57664e9SAndroid Build Coastguard Worker }
4774*d57664e9SAndroid Build Coastguard Worker
4775*d57664e9SAndroid Build Coastguard Worker if (node->getElementNamespace().size() != 0) {
4776*d57664e9SAndroid Build Coastguard Worker // Not something we care about.
4777*d57664e9SAndroid Build Coastguard Worker return false;
4778*d57664e9SAndroid Build Coastguard Worker }
4779*d57664e9SAndroid Build Coastguard Worker
4780*d57664e9SAndroid Build Coastguard Worker int versionedSdk = 0;
4781*d57664e9SAndroid Build Coastguard Worker if (node->getElementName() == String16("adaptive-icon")) {
4782*d57664e9SAndroid Build Coastguard Worker versionedSdk = SDK_O;
4783*d57664e9SAndroid Build Coastguard Worker }
4784*d57664e9SAndroid Build Coastguard Worker
4785*d57664e9SAndroid Build Coastguard Worker const int minSdkVersion = getMinSdkVersion(bundle);
4786*d57664e9SAndroid Build Coastguard Worker const ConfigDescription config(target->getGroupEntry().toParams());
4787*d57664e9SAndroid Build Coastguard Worker if (versionedSdk <= minSdkVersion || versionedSdk <= config.sdkVersion) {
4788*d57664e9SAndroid Build Coastguard Worker return false;
4789*d57664e9SAndroid Build Coastguard Worker }
4790*d57664e9SAndroid Build Coastguard Worker
4791*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
4792*d57664e9SAndroid Build Coastguard Worker String16(target->getResourceType()), resourceName);
4793*d57664e9SAndroid Build Coastguard Worker if (!shouldGenerateVersionedResource(cl, config, versionedSdk)) {
4794*d57664e9SAndroid Build Coastguard Worker return false;
4795*d57664e9SAndroid Build Coastguard Worker }
4796*d57664e9SAndroid Build Coastguard Worker
4797*d57664e9SAndroid Build Coastguard Worker // Remove the original entry.
4798*d57664e9SAndroid Build Coastguard Worker cl->removeEntry(config);
4799*d57664e9SAndroid Build Coastguard Worker
4800*d57664e9SAndroid Build Coastguard Worker // We need to wholesale version this file.
4801*d57664e9SAndroid Build Coastguard Worker ConfigDescription newConfig(config);
4802*d57664e9SAndroid Build Coastguard Worker newConfig.sdkVersion = versionedSdk;
4803*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
4804*d57664e9SAndroid Build Coastguard Worker AaptGroupEntry(newConfig), target->getResourceType());
4805*d57664e9SAndroid Build Coastguard Worker String8 resPath = String8::format("res/%s/%s.xml",
4806*d57664e9SAndroid Build Coastguard Worker newFile->getGroupEntry().toDirName(target->getResourceType()).c_str(),
4807*d57664e9SAndroid Build Coastguard Worker String8(resourceName).c_str());
4808*d57664e9SAndroid Build Coastguard Worker convertToResPath(resPath);
4809*d57664e9SAndroid Build Coastguard Worker
4810*d57664e9SAndroid Build Coastguard Worker // Add a resource table entry.
4811*d57664e9SAndroid Build Coastguard Worker addEntry(SourcePos(),
4812*d57664e9SAndroid Build Coastguard Worker String16(mAssets->getPackage()),
4813*d57664e9SAndroid Build Coastguard Worker String16(target->getResourceType()),
4814*d57664e9SAndroid Build Coastguard Worker resourceName,
4815*d57664e9SAndroid Build Coastguard Worker String16(resPath),
4816*d57664e9SAndroid Build Coastguard Worker NULL,
4817*d57664e9SAndroid Build Coastguard Worker &newConfig);
4818*d57664e9SAndroid Build Coastguard Worker
4819*d57664e9SAndroid Build Coastguard Worker // Schedule this to be compiled.
4820*d57664e9SAndroid Build Coastguard Worker CompileResourceWorkItem item;
4821*d57664e9SAndroid Build Coastguard Worker item.resourceName = resourceName;
4822*d57664e9SAndroid Build Coastguard Worker item.resPath = resPath;
4823*d57664e9SAndroid Build Coastguard Worker item.file = newFile;
4824*d57664e9SAndroid Build Coastguard Worker item.xmlRoot = root->clone();
4825*d57664e9SAndroid Build Coastguard Worker item.needsCompiling = true;
4826*d57664e9SAndroid Build Coastguard Worker mWorkQueue.push(item);
4827*d57664e9SAndroid Build Coastguard Worker
4828*d57664e9SAndroid Build Coastguard Worker // Now mark the old entry as deleted.
4829*d57664e9SAndroid Build Coastguard Worker return true;
4830*d57664e9SAndroid Build Coastguard Worker }
4831*d57664e9SAndroid Build Coastguard Worker
modifyForCompat(const Bundle * bundle,const String16 & resourceName,const sp<AaptFile> & target,const sp<XMLNode> & root)4832*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::modifyForCompat(const Bundle* bundle,
4833*d57664e9SAndroid Build Coastguard Worker const String16& resourceName,
4834*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target,
4835*d57664e9SAndroid Build Coastguard Worker const sp<XMLNode>& root) {
4836*d57664e9SAndroid Build Coastguard Worker const String16 vector16("vector");
4837*d57664e9SAndroid Build Coastguard Worker const String16 animatedVector16("animated-vector");
4838*d57664e9SAndroid Build Coastguard Worker const String16 pathInterpolator16("pathInterpolator");
4839*d57664e9SAndroid Build Coastguard Worker const String16 objectAnimator16("objectAnimator");
4840*d57664e9SAndroid Build Coastguard Worker const String16 gradient16("gradient");
4841*d57664e9SAndroid Build Coastguard Worker const String16 animatedSelector16("animated-selector");
4842*d57664e9SAndroid Build Coastguard Worker
4843*d57664e9SAndroid Build Coastguard Worker const int minSdk = getMinSdkVersion(bundle);
4844*d57664e9SAndroid Build Coastguard Worker if (minSdk >= SDK_LOLLIPOP_MR1) {
4845*d57664e9SAndroid Build Coastguard Worker // Lollipop MR1 and up handles public attributes differently, no
4846*d57664e9SAndroid Build Coastguard Worker // need to do any compat modifications.
4847*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4848*d57664e9SAndroid Build Coastguard Worker }
4849*d57664e9SAndroid Build Coastguard Worker
4850*d57664e9SAndroid Build Coastguard Worker const ConfigDescription config(target->getGroupEntry().toParams());
4851*d57664e9SAndroid Build Coastguard Worker if (target->getResourceType() == "" || config.sdkVersion >= SDK_LOLLIPOP_MR1) {
4852*d57664e9SAndroid Build Coastguard Worker // Skip resources that have no type (AndroidManifest.xml) or are already version qualified
4853*d57664e9SAndroid Build Coastguard Worker // with v21 or higher.
4854*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4855*d57664e9SAndroid Build Coastguard Worker }
4856*d57664e9SAndroid Build Coastguard Worker
4857*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> newRoot = NULL;
4858*d57664e9SAndroid Build Coastguard Worker int sdkVersionToGenerate = SDK_LOLLIPOP_MR1;
4859*d57664e9SAndroid Build Coastguard Worker
4860*d57664e9SAndroid Build Coastguard Worker Vector<sp<XMLNode> > nodesToVisit;
4861*d57664e9SAndroid Build Coastguard Worker nodesToVisit.push(root);
4862*d57664e9SAndroid Build Coastguard Worker while (!nodesToVisit.empty()) {
4863*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = nodesToVisit.top();
4864*d57664e9SAndroid Build Coastguard Worker nodesToVisit.pop();
4865*d57664e9SAndroid Build Coastguard Worker
4866*d57664e9SAndroid Build Coastguard Worker if (bundle->getNoVersionVectors() && (node->getElementName() == vector16 ||
4867*d57664e9SAndroid Build Coastguard Worker node->getElementName() == animatedVector16 ||
4868*d57664e9SAndroid Build Coastguard Worker node->getElementName() == objectAnimator16 ||
4869*d57664e9SAndroid Build Coastguard Worker node->getElementName() == pathInterpolator16 ||
4870*d57664e9SAndroid Build Coastguard Worker node->getElementName() == gradient16 ||
4871*d57664e9SAndroid Build Coastguard Worker node->getElementName() == animatedSelector16)) {
4872*d57664e9SAndroid Build Coastguard Worker // We were told not to version vector tags, so skip the children here.
4873*d57664e9SAndroid Build Coastguard Worker continue;
4874*d57664e9SAndroid Build Coastguard Worker }
4875*d57664e9SAndroid Build Coastguard Worker
4876*d57664e9SAndroid Build Coastguard Worker if (bundle->getNoVersionTransitions() && (IsTransitionElement(node->getElementName()))) {
4877*d57664e9SAndroid Build Coastguard Worker // We were told not to version transition tags, so skip the children here.
4878*d57664e9SAndroid Build Coastguard Worker continue;
4879*d57664e9SAndroid Build Coastguard Worker }
4880*d57664e9SAndroid Build Coastguard Worker
4881*d57664e9SAndroid Build Coastguard Worker const Vector<XMLNode::attribute_entry>& attrs = node->getAttributes();
4882*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < attrs.size(); i++) {
4883*d57664e9SAndroid Build Coastguard Worker const XMLNode::attribute_entry& attr = attrs[i];
4884*d57664e9SAndroid Build Coastguard Worker const int sdkLevel = getPublicAttributeSdkLevel(attr.nameResId);
4885*d57664e9SAndroid Build Coastguard Worker if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
4886*d57664e9SAndroid Build Coastguard Worker if (newRoot == NULL) {
4887*d57664e9SAndroid Build Coastguard Worker newRoot = root->clone();
4888*d57664e9SAndroid Build Coastguard Worker }
4889*d57664e9SAndroid Build Coastguard Worker
4890*d57664e9SAndroid Build Coastguard Worker // Find the smallest sdk version that we need to synthesize for
4891*d57664e9SAndroid Build Coastguard Worker // and do that one. Subsequent versions will be processed on
4892*d57664e9SAndroid Build Coastguard Worker // the next pass.
4893*d57664e9SAndroid Build Coastguard Worker sdkVersionToGenerate = std::min(sdkLevel, sdkVersionToGenerate);
4894*d57664e9SAndroid Build Coastguard Worker
4895*d57664e9SAndroid Build Coastguard Worker if (bundle->getVerbose()) {
4896*d57664e9SAndroid Build Coastguard Worker SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
4897*d57664e9SAndroid Build Coastguard Worker "removing attribute %s%s%s from <%s>",
4898*d57664e9SAndroid Build Coastguard Worker String8(attr.ns).c_str(),
4899*d57664e9SAndroid Build Coastguard Worker (attr.ns.size() == 0 ? "" : ":"),
4900*d57664e9SAndroid Build Coastguard Worker String8(attr.name).c_str(),
4901*d57664e9SAndroid Build Coastguard Worker String8(node->getElementName()).c_str());
4902*d57664e9SAndroid Build Coastguard Worker }
4903*d57664e9SAndroid Build Coastguard Worker node->removeAttribute(i);
4904*d57664e9SAndroid Build Coastguard Worker i--;
4905*d57664e9SAndroid Build Coastguard Worker }
4906*d57664e9SAndroid Build Coastguard Worker }
4907*d57664e9SAndroid Build Coastguard Worker
4908*d57664e9SAndroid Build Coastguard Worker // Schedule a visit to the children.
4909*d57664e9SAndroid Build Coastguard Worker const Vector<sp<XMLNode> >& children = node->getChildren();
4910*d57664e9SAndroid Build Coastguard Worker const size_t childCount = children.size();
4911*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < childCount; i++) {
4912*d57664e9SAndroid Build Coastguard Worker nodesToVisit.push(children[i]);
4913*d57664e9SAndroid Build Coastguard Worker }
4914*d57664e9SAndroid Build Coastguard Worker }
4915*d57664e9SAndroid Build Coastguard Worker
4916*d57664e9SAndroid Build Coastguard Worker if (newRoot == NULL) {
4917*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4918*d57664e9SAndroid Build Coastguard Worker }
4919*d57664e9SAndroid Build Coastguard Worker
4920*d57664e9SAndroid Build Coastguard Worker // Look to see if we already have an overriding v21 configuration.
4921*d57664e9SAndroid Build Coastguard Worker sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
4922*d57664e9SAndroid Build Coastguard Worker String16(target->getResourceType()), resourceName);
4923*d57664e9SAndroid Build Coastguard Worker if (shouldGenerateVersionedResource(cl, config, sdkVersionToGenerate)) {
4924*d57664e9SAndroid Build Coastguard Worker // We don't have an overriding entry for v21, so we must duplicate this one.
4925*d57664e9SAndroid Build Coastguard Worker ConfigDescription newConfig(config);
4926*d57664e9SAndroid Build Coastguard Worker newConfig.sdkVersion = sdkVersionToGenerate;
4927*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
4928*d57664e9SAndroid Build Coastguard Worker AaptGroupEntry(newConfig), target->getResourceType());
4929*d57664e9SAndroid Build Coastguard Worker String8 resPath = String8::format("res/%s/%s.xml",
4930*d57664e9SAndroid Build Coastguard Worker newFile->getGroupEntry().toDirName(target->getResourceType()).c_str(),
4931*d57664e9SAndroid Build Coastguard Worker String8(resourceName).c_str());
4932*d57664e9SAndroid Build Coastguard Worker convertToResPath(resPath);
4933*d57664e9SAndroid Build Coastguard Worker
4934*d57664e9SAndroid Build Coastguard Worker // Add a resource table entry.
4935*d57664e9SAndroid Build Coastguard Worker if (bundle->getVerbose()) {
4936*d57664e9SAndroid Build Coastguard Worker SourcePos(target->getSourceFile(), -1).printf(
4937*d57664e9SAndroid Build Coastguard Worker "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
4938*d57664e9SAndroid Build Coastguard Worker newConfig.sdkVersion,
4939*d57664e9SAndroid Build Coastguard Worker mAssets->getPackage().c_str(),
4940*d57664e9SAndroid Build Coastguard Worker newFile->getResourceType().c_str(),
4941*d57664e9SAndroid Build Coastguard Worker String8(resourceName).c_str(),
4942*d57664e9SAndroid Build Coastguard Worker newConfig.toString().c_str());
4943*d57664e9SAndroid Build Coastguard Worker }
4944*d57664e9SAndroid Build Coastguard Worker
4945*d57664e9SAndroid Build Coastguard Worker addEntry(SourcePos(),
4946*d57664e9SAndroid Build Coastguard Worker String16(mAssets->getPackage()),
4947*d57664e9SAndroid Build Coastguard Worker String16(target->getResourceType()),
4948*d57664e9SAndroid Build Coastguard Worker resourceName,
4949*d57664e9SAndroid Build Coastguard Worker String16(resPath),
4950*d57664e9SAndroid Build Coastguard Worker NULL,
4951*d57664e9SAndroid Build Coastguard Worker &newConfig);
4952*d57664e9SAndroid Build Coastguard Worker
4953*d57664e9SAndroid Build Coastguard Worker // Schedule this to be compiled.
4954*d57664e9SAndroid Build Coastguard Worker CompileResourceWorkItem item;
4955*d57664e9SAndroid Build Coastguard Worker item.resourceName = resourceName;
4956*d57664e9SAndroid Build Coastguard Worker item.resPath = resPath;
4957*d57664e9SAndroid Build Coastguard Worker item.file = newFile;
4958*d57664e9SAndroid Build Coastguard Worker item.xmlRoot = newRoot;
4959*d57664e9SAndroid Build Coastguard Worker item.needsCompiling = false; // This step occurs after we parse/assign, so we don't need
4960*d57664e9SAndroid Build Coastguard Worker // to do it again.
4961*d57664e9SAndroid Build Coastguard Worker mWorkQueue.push(item);
4962*d57664e9SAndroid Build Coastguard Worker }
4963*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
4964*d57664e9SAndroid Build Coastguard Worker }
4965*d57664e9SAndroid Build Coastguard Worker
getDensityVaryingResources(KeyedVector<Symbol,Vector<SymbolDefinition>> & resources)4966*d57664e9SAndroid Build Coastguard Worker void ResourceTable::getDensityVaryingResources(
4967*d57664e9SAndroid Build Coastguard Worker KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) {
4968*d57664e9SAndroid Build Coastguard Worker const ConfigDescription nullConfig;
4969*d57664e9SAndroid Build Coastguard Worker
4970*d57664e9SAndroid Build Coastguard Worker const size_t packageCount = mOrderedPackages.size();
4971*d57664e9SAndroid Build Coastguard Worker for (size_t p = 0; p < packageCount; p++) {
4972*d57664e9SAndroid Build Coastguard Worker const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes();
4973*d57664e9SAndroid Build Coastguard Worker const size_t typeCount = types.size();
4974*d57664e9SAndroid Build Coastguard Worker for (size_t t = 0; t < typeCount; t++) {
4975*d57664e9SAndroid Build Coastguard Worker const sp<Type>& type = types[t];
4976*d57664e9SAndroid Build Coastguard Worker if (type == NULL) {
4977*d57664e9SAndroid Build Coastguard Worker continue;
4978*d57664e9SAndroid Build Coastguard Worker }
4979*d57664e9SAndroid Build Coastguard Worker
4980*d57664e9SAndroid Build Coastguard Worker const Vector<sp<ConfigList> >& configs = type->getOrderedConfigs();
4981*d57664e9SAndroid Build Coastguard Worker const size_t configCount = configs.size();
4982*d57664e9SAndroid Build Coastguard Worker for (size_t c = 0; c < configCount; c++) {
4983*d57664e9SAndroid Build Coastguard Worker const sp<ConfigList>& configList = configs[c];
4984*d57664e9SAndroid Build Coastguard Worker if (configList == NULL) {
4985*d57664e9SAndroid Build Coastguard Worker continue;
4986*d57664e9SAndroid Build Coastguard Worker }
4987*d57664e9SAndroid Build Coastguard Worker
4988*d57664e9SAndroid Build Coastguard Worker const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries
4989*d57664e9SAndroid Build Coastguard Worker = configList->getEntries();
4990*d57664e9SAndroid Build Coastguard Worker const size_t configEntryCount = configEntries.size();
4991*d57664e9SAndroid Build Coastguard Worker for (size_t ce = 0; ce < configEntryCount; ce++) {
4992*d57664e9SAndroid Build Coastguard Worker const sp<Entry>& entry = configEntries.valueAt(ce);
4993*d57664e9SAndroid Build Coastguard Worker if (entry == NULL) {
4994*d57664e9SAndroid Build Coastguard Worker continue;
4995*d57664e9SAndroid Build Coastguard Worker }
4996*d57664e9SAndroid Build Coastguard Worker
4997*d57664e9SAndroid Build Coastguard Worker const ConfigDescription& config = configEntries.keyAt(ce);
4998*d57664e9SAndroid Build Coastguard Worker if (AaptConfig::isDensityOnly(config)) {
4999*d57664e9SAndroid Build Coastguard Worker // This configuration only varies with regards to density.
5000*d57664e9SAndroid Build Coastguard Worker const Symbol symbol(
5001*d57664e9SAndroid Build Coastguard Worker mOrderedPackages[p]->getName(),
5002*d57664e9SAndroid Build Coastguard Worker type->getName(),
5003*d57664e9SAndroid Build Coastguard Worker configList->getName(),
5004*d57664e9SAndroid Build Coastguard Worker getResId(mOrderedPackages[p], types[t],
5005*d57664e9SAndroid Build Coastguard Worker configList->getEntryIndex()));
5006*d57664e9SAndroid Build Coastguard Worker
5007*d57664e9SAndroid Build Coastguard Worker
5008*d57664e9SAndroid Build Coastguard Worker AaptUtil::appendValue(resources, symbol,
5009*d57664e9SAndroid Build Coastguard Worker SymbolDefinition(symbol, config, entry->getPos()));
5010*d57664e9SAndroid Build Coastguard Worker }
5011*d57664e9SAndroid Build Coastguard Worker }
5012*d57664e9SAndroid Build Coastguard Worker }
5013*d57664e9SAndroid Build Coastguard Worker }
5014*d57664e9SAndroid Build Coastguard Worker }
5015*d57664e9SAndroid Build Coastguard Worker }
5016*d57664e9SAndroid Build Coastguard Worker
buildNamespace(const String16 & package)5017*d57664e9SAndroid Build Coastguard Worker static String16 buildNamespace(const String16& package) {
5018*d57664e9SAndroid Build Coastguard Worker return String16("http://schemas.android.com/apk/res/") + package;
5019*d57664e9SAndroid Build Coastguard Worker }
5020*d57664e9SAndroid Build Coastguard Worker
findOnlyChildElement(const sp<XMLNode> & parent)5021*d57664e9SAndroid Build Coastguard Worker static sp<XMLNode> findOnlyChildElement(const sp<XMLNode>& parent) {
5022*d57664e9SAndroid Build Coastguard Worker const Vector<sp<XMLNode> >& children = parent->getChildren();
5023*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> onlyChild;
5024*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < children.size(); i++) {
5025*d57664e9SAndroid Build Coastguard Worker if (children[i]->getType() != XMLNode::TYPE_CDATA) {
5026*d57664e9SAndroid Build Coastguard Worker if (onlyChild != NULL) {
5027*d57664e9SAndroid Build Coastguard Worker return NULL;
5028*d57664e9SAndroid Build Coastguard Worker }
5029*d57664e9SAndroid Build Coastguard Worker onlyChild = children[i];
5030*d57664e9SAndroid Build Coastguard Worker }
5031*d57664e9SAndroid Build Coastguard Worker }
5032*d57664e9SAndroid Build Coastguard Worker return onlyChild;
5033*d57664e9SAndroid Build Coastguard Worker }
5034*d57664e9SAndroid Build Coastguard Worker
5035*d57664e9SAndroid Build Coastguard Worker /**
5036*d57664e9SAndroid Build Coastguard Worker * Detects use of the `bundle' format and extracts nested resources into their own top level
5037*d57664e9SAndroid Build Coastguard Worker * resources. The bundle format looks like this:
5038*d57664e9SAndroid Build Coastguard Worker *
5039*d57664e9SAndroid Build Coastguard Worker * <!-- res/drawable/bundle.xml -->
5040*d57664e9SAndroid Build Coastguard Worker * <animated-vector xmlns:aapt="http://schemas.android.com/aapt">
5041*d57664e9SAndroid Build Coastguard Worker * <aapt:attr name="android:drawable">
5042*d57664e9SAndroid Build Coastguard Worker * <vector android:width="60dp"
5043*d57664e9SAndroid Build Coastguard Worker * android:height="60dp">
5044*d57664e9SAndroid Build Coastguard Worker * <path android:name="v"
5045*d57664e9SAndroid Build Coastguard Worker * android:fillColor="#000000"
5046*d57664e9SAndroid Build Coastguard Worker * android:pathData="M300,70 l 0,-70 70,..." />
5047*d57664e9SAndroid Build Coastguard Worker * </vector>
5048*d57664e9SAndroid Build Coastguard Worker * </aapt:attr>
5049*d57664e9SAndroid Build Coastguard Worker * </animated-vector>
5050*d57664e9SAndroid Build Coastguard Worker *
5051*d57664e9SAndroid Build Coastguard Worker * When AAPT sees the <aapt:attr> tag, it will extract its single element and its children
5052*d57664e9SAndroid Build Coastguard Worker * into a new high-level resource, assigning it a name and ID. Then value of the `name`
5053*d57664e9SAndroid Build Coastguard Worker * attribute must be a resource attribute. That resource attribute is inserted into the parent
5054*d57664e9SAndroid Build Coastguard Worker * with the reference to the extracted resource as the value.
5055*d57664e9SAndroid Build Coastguard Worker *
5056*d57664e9SAndroid Build Coastguard Worker * <!-- res/drawable/bundle.xml -->
5057*d57664e9SAndroid Build Coastguard Worker * <animated-vector android:drawable="@drawable/bundle_1.xml">
5058*d57664e9SAndroid Build Coastguard Worker * </animated-vector>
5059*d57664e9SAndroid Build Coastguard Worker *
5060*d57664e9SAndroid Build Coastguard Worker * <!-- res/drawable/bundle_1.xml -->
5061*d57664e9SAndroid Build Coastguard Worker * <vector android:width="60dp"
5062*d57664e9SAndroid Build Coastguard Worker * android:height="60dp">
5063*d57664e9SAndroid Build Coastguard Worker * <path android:name="v"
5064*d57664e9SAndroid Build Coastguard Worker * android:fillColor="#000000"
5065*d57664e9SAndroid Build Coastguard Worker * android:pathData="M300,70 l 0,-70 70,..." />
5066*d57664e9SAndroid Build Coastguard Worker * </vector>
5067*d57664e9SAndroid Build Coastguard Worker */
processBundleFormat(const Bundle * bundle,const String16 & resourceName,const sp<AaptFile> & target,const sp<XMLNode> & root)5068*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::processBundleFormat(const Bundle* bundle,
5069*d57664e9SAndroid Build Coastguard Worker const String16& resourceName,
5070*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target,
5071*d57664e9SAndroid Build Coastguard Worker const sp<XMLNode>& root) {
5072*d57664e9SAndroid Build Coastguard Worker Vector<sp<XMLNode> > namespaces;
5073*d57664e9SAndroid Build Coastguard Worker if (root->getType() == XMLNode::TYPE_NAMESPACE) {
5074*d57664e9SAndroid Build Coastguard Worker namespaces.push(root);
5075*d57664e9SAndroid Build Coastguard Worker }
5076*d57664e9SAndroid Build Coastguard Worker return processBundleFormatImpl(bundle, resourceName, target, root, &namespaces);
5077*d57664e9SAndroid Build Coastguard Worker }
5078*d57664e9SAndroid Build Coastguard Worker
processBundleFormatImpl(const Bundle * bundle,const String16 & resourceName,const sp<AaptFile> & target,const sp<XMLNode> & parent,Vector<sp<XMLNode>> * namespaces)5079*d57664e9SAndroid Build Coastguard Worker status_t ResourceTable::processBundleFormatImpl(const Bundle* bundle,
5080*d57664e9SAndroid Build Coastguard Worker const String16& resourceName,
5081*d57664e9SAndroid Build Coastguard Worker const sp<AaptFile>& target,
5082*d57664e9SAndroid Build Coastguard Worker const sp<XMLNode>& parent,
5083*d57664e9SAndroid Build Coastguard Worker Vector<sp<XMLNode> >* namespaces) {
5084*d57664e9SAndroid Build Coastguard Worker const String16 kAaptNamespaceUri16("http://schemas.android.com/aapt");
5085*d57664e9SAndroid Build Coastguard Worker const String16 kName16("name");
5086*d57664e9SAndroid Build Coastguard Worker const String16 kAttr16("attr");
5087*d57664e9SAndroid Build Coastguard Worker const String16 kAssetPackage16(mAssets->getPackage());
5088*d57664e9SAndroid Build Coastguard Worker
5089*d57664e9SAndroid Build Coastguard Worker Vector<sp<XMLNode> >& children = parent->getChildren();
5090*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < children.size(); i++) {
5091*d57664e9SAndroid Build Coastguard Worker const sp<XMLNode>& child = children[i];
5092*d57664e9SAndroid Build Coastguard Worker
5093*d57664e9SAndroid Build Coastguard Worker if (child->getType() == XMLNode::TYPE_CDATA) {
5094*d57664e9SAndroid Build Coastguard Worker continue;
5095*d57664e9SAndroid Build Coastguard Worker } else if (child->getType() == XMLNode::TYPE_NAMESPACE) {
5096*d57664e9SAndroid Build Coastguard Worker namespaces->push(child);
5097*d57664e9SAndroid Build Coastguard Worker }
5098*d57664e9SAndroid Build Coastguard Worker
5099*d57664e9SAndroid Build Coastguard Worker if (child->getElementNamespace() != kAaptNamespaceUri16 ||
5100*d57664e9SAndroid Build Coastguard Worker child->getElementName() != kAttr16) {
5101*d57664e9SAndroid Build Coastguard Worker status_t result = processBundleFormatImpl(bundle, resourceName, target, child,
5102*d57664e9SAndroid Build Coastguard Worker namespaces);
5103*d57664e9SAndroid Build Coastguard Worker if (result != NO_ERROR) {
5104*d57664e9SAndroid Build Coastguard Worker return result;
5105*d57664e9SAndroid Build Coastguard Worker }
5106*d57664e9SAndroid Build Coastguard Worker
5107*d57664e9SAndroid Build Coastguard Worker if (child->getType() == XMLNode::TYPE_NAMESPACE) {
5108*d57664e9SAndroid Build Coastguard Worker namespaces->pop();
5109*d57664e9SAndroid Build Coastguard Worker }
5110*d57664e9SAndroid Build Coastguard Worker continue;
5111*d57664e9SAndroid Build Coastguard Worker }
5112*d57664e9SAndroid Build Coastguard Worker
5113*d57664e9SAndroid Build Coastguard Worker // This is the <aapt:attr> tag. Look for the 'name' attribute.
5114*d57664e9SAndroid Build Coastguard Worker SourcePos source(child->getFilename(), child->getStartLineNumber());
5115*d57664e9SAndroid Build Coastguard Worker
5116*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> nestedRoot = findOnlyChildElement(child);
5117*d57664e9SAndroid Build Coastguard Worker if (nestedRoot == NULL) {
5118*d57664e9SAndroid Build Coastguard Worker source.error("<%s:%s> must have exactly one child element",
5119*d57664e9SAndroid Build Coastguard Worker String8(child->getElementNamespace()).c_str(),
5120*d57664e9SAndroid Build Coastguard Worker String8(child->getElementName()).c_str());
5121*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
5122*d57664e9SAndroid Build Coastguard Worker }
5123*d57664e9SAndroid Build Coastguard Worker
5124*d57664e9SAndroid Build Coastguard Worker // Find the special attribute 'parent-attr'. This attribute's value contains
5125*d57664e9SAndroid Build Coastguard Worker // the resource attribute for which this element should be assigned in the parent.
5126*d57664e9SAndroid Build Coastguard Worker const XMLNode::attribute_entry* attr = child->getAttribute(String16(), kName16);
5127*d57664e9SAndroid Build Coastguard Worker if (attr == NULL) {
5128*d57664e9SAndroid Build Coastguard Worker source.error("inline resource definition must specify an attribute via 'name'");
5129*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
5130*d57664e9SAndroid Build Coastguard Worker }
5131*d57664e9SAndroid Build Coastguard Worker
5132*d57664e9SAndroid Build Coastguard Worker // Parse the attribute name.
5133*d57664e9SAndroid Build Coastguard Worker const char* errorMsg = NULL;
5134*d57664e9SAndroid Build Coastguard Worker String16 attrPackage, attrType, attrName;
5135*d57664e9SAndroid Build Coastguard Worker bool result = ResTable::expandResourceRef(attr->string.c_str(),
5136*d57664e9SAndroid Build Coastguard Worker attr->string.size(),
5137*d57664e9SAndroid Build Coastguard Worker &attrPackage, &attrType, &attrName,
5138*d57664e9SAndroid Build Coastguard Worker &kAttr16, &kAssetPackage16,
5139*d57664e9SAndroid Build Coastguard Worker &errorMsg, NULL);
5140*d57664e9SAndroid Build Coastguard Worker if (!result) {
5141*d57664e9SAndroid Build Coastguard Worker source.error("invalid attribute name for 'name': %s", errorMsg);
5142*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
5143*d57664e9SAndroid Build Coastguard Worker }
5144*d57664e9SAndroid Build Coastguard Worker
5145*d57664e9SAndroid Build Coastguard Worker if (attrType != kAttr16) {
5146*d57664e9SAndroid Build Coastguard Worker // The value of the 'name' attribute must be an attribute reference.
5147*d57664e9SAndroid Build Coastguard Worker source.error("value of 'name' must be an attribute reference.");
5148*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
5149*d57664e9SAndroid Build Coastguard Worker }
5150*d57664e9SAndroid Build Coastguard Worker
5151*d57664e9SAndroid Build Coastguard Worker // Generate a name for this nested resource and try to add it to the table.
5152*d57664e9SAndroid Build Coastguard Worker // We do this in a loop because the name may be taken, in which case we will
5153*d57664e9SAndroid Build Coastguard Worker // increment a suffix until we succeed.
5154*d57664e9SAndroid Build Coastguard Worker String8 nestedResourceName;
5155*d57664e9SAndroid Build Coastguard Worker String8 nestedResourcePath;
5156*d57664e9SAndroid Build Coastguard Worker int suffix = 1;
5157*d57664e9SAndroid Build Coastguard Worker while (true) {
5158*d57664e9SAndroid Build Coastguard Worker // This child element will be extracted into its own resource file.
5159*d57664e9SAndroid Build Coastguard Worker // Generate a name and path for it from its parent.
5160*d57664e9SAndroid Build Coastguard Worker nestedResourceName = String8::format("%s_%d",
5161*d57664e9SAndroid Build Coastguard Worker String8(resourceName).c_str(), suffix++);
5162*d57664e9SAndroid Build Coastguard Worker nestedResourcePath = String8::format("res/%s/%s.xml",
5163*d57664e9SAndroid Build Coastguard Worker target->getGroupEntry().toDirName(target->getResourceType())
5164*d57664e9SAndroid Build Coastguard Worker .c_str(),
5165*d57664e9SAndroid Build Coastguard Worker nestedResourceName.c_str());
5166*d57664e9SAndroid Build Coastguard Worker
5167*d57664e9SAndroid Build Coastguard Worker // Lookup or create the entry for this name.
5168*d57664e9SAndroid Build Coastguard Worker sp<Entry> entry = getEntry(kAssetPackage16,
5169*d57664e9SAndroid Build Coastguard Worker String16(target->getResourceType()),
5170*d57664e9SAndroid Build Coastguard Worker String16(nestedResourceName),
5171*d57664e9SAndroid Build Coastguard Worker source,
5172*d57664e9SAndroid Build Coastguard Worker false,
5173*d57664e9SAndroid Build Coastguard Worker &target->getGroupEntry().toParams(),
5174*d57664e9SAndroid Build Coastguard Worker true);
5175*d57664e9SAndroid Build Coastguard Worker if (entry == NULL) {
5176*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
5177*d57664e9SAndroid Build Coastguard Worker }
5178*d57664e9SAndroid Build Coastguard Worker
5179*d57664e9SAndroid Build Coastguard Worker if (entry->getType() == Entry::TYPE_UNKNOWN) {
5180*d57664e9SAndroid Build Coastguard Worker // The value for this resource has never been set,
5181*d57664e9SAndroid Build Coastguard Worker // meaning we're good!
5182*d57664e9SAndroid Build Coastguard Worker entry->setItem(source, String16(nestedResourcePath));
5183*d57664e9SAndroid Build Coastguard Worker break;
5184*d57664e9SAndroid Build Coastguard Worker }
5185*d57664e9SAndroid Build Coastguard Worker
5186*d57664e9SAndroid Build Coastguard Worker // We failed (name already exists), so try with a different name
5187*d57664e9SAndroid Build Coastguard Worker // (increment the suffix).
5188*d57664e9SAndroid Build Coastguard Worker }
5189*d57664e9SAndroid Build Coastguard Worker
5190*d57664e9SAndroid Build Coastguard Worker if (bundle->getVerbose()) {
5191*d57664e9SAndroid Build Coastguard Worker source.printf("generating nested resource %s:%s/%s",
5192*d57664e9SAndroid Build Coastguard Worker mAssets->getPackage().c_str(), target->getResourceType().c_str(),
5193*d57664e9SAndroid Build Coastguard Worker nestedResourceName.c_str());
5194*d57664e9SAndroid Build Coastguard Worker }
5195*d57664e9SAndroid Build Coastguard Worker
5196*d57664e9SAndroid Build Coastguard Worker // Build the attribute reference and assign it to the parent.
5197*d57664e9SAndroid Build Coastguard Worker String16 nestedResourceRef = String16(String8::format("@%s:%s/%s",
5198*d57664e9SAndroid Build Coastguard Worker mAssets->getPackage().c_str(), target->getResourceType().c_str(),
5199*d57664e9SAndroid Build Coastguard Worker nestedResourceName.c_str()));
5200*d57664e9SAndroid Build Coastguard Worker
5201*d57664e9SAndroid Build Coastguard Worker String16 attrNs = buildNamespace(attrPackage);
5202*d57664e9SAndroid Build Coastguard Worker if (parent->getAttribute(attrNs, attrName) != NULL) {
5203*d57664e9SAndroid Build Coastguard Worker SourcePos(parent->getFilename(), parent->getStartLineNumber())
5204*d57664e9SAndroid Build Coastguard Worker .error("parent of nested resource already defines attribute '%s:%s'",
5205*d57664e9SAndroid Build Coastguard Worker String8(attrPackage).c_str(), String8(attrName).c_str());
5206*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
5207*d57664e9SAndroid Build Coastguard Worker }
5208*d57664e9SAndroid Build Coastguard Worker
5209*d57664e9SAndroid Build Coastguard Worker // Add the reference to the inline resource.
5210*d57664e9SAndroid Build Coastguard Worker parent->addAttribute(attrNs, attrName, nestedResourceRef);
5211*d57664e9SAndroid Build Coastguard Worker
5212*d57664e9SAndroid Build Coastguard Worker // Remove the <aapt:attr> child element from here.
5213*d57664e9SAndroid Build Coastguard Worker children.removeAt(i);
5214*d57664e9SAndroid Build Coastguard Worker i--;
5215*d57664e9SAndroid Build Coastguard Worker
5216*d57664e9SAndroid Build Coastguard Worker // Append all namespace declarations that we've seen on this branch in the XML tree
5217*d57664e9SAndroid Build Coastguard Worker // to this resource.
5218*d57664e9SAndroid Build Coastguard Worker // We do this because the order of namespace declarations and prefix usage is determined
5219*d57664e9SAndroid Build Coastguard Worker // by the developer and we do not want to override any decisions. Be conservative.
5220*d57664e9SAndroid Build Coastguard Worker for (size_t nsIndex = namespaces->size(); nsIndex > 0; nsIndex--) {
5221*d57664e9SAndroid Build Coastguard Worker const sp<XMLNode>& ns = namespaces->itemAt(nsIndex - 1);
5222*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> newNs = XMLNode::newNamespace(ns->getFilename(), ns->getNamespacePrefix(),
5223*d57664e9SAndroid Build Coastguard Worker ns->getNamespaceUri());
5224*d57664e9SAndroid Build Coastguard Worker newNs->addChild(nestedRoot);
5225*d57664e9SAndroid Build Coastguard Worker nestedRoot = newNs;
5226*d57664e9SAndroid Build Coastguard Worker }
5227*d57664e9SAndroid Build Coastguard Worker
5228*d57664e9SAndroid Build Coastguard Worker // Schedule compilation of the nested resource.
5229*d57664e9SAndroid Build Coastguard Worker CompileResourceWorkItem workItem;
5230*d57664e9SAndroid Build Coastguard Worker workItem.resPath = nestedResourcePath;
5231*d57664e9SAndroid Build Coastguard Worker workItem.resourceName = String16(nestedResourceName);
5232*d57664e9SAndroid Build Coastguard Worker workItem.xmlRoot = nestedRoot;
5233*d57664e9SAndroid Build Coastguard Worker workItem.file = new AaptFile(target->getSourceFile(), target->getGroupEntry(),
5234*d57664e9SAndroid Build Coastguard Worker target->getResourceType());
5235*d57664e9SAndroid Build Coastguard Worker mWorkQueue.push(workItem);
5236*d57664e9SAndroid Build Coastguard Worker }
5237*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
5238*d57664e9SAndroid Build Coastguard Worker }
5239