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 "XMLNode.h"
8*d57664e9SAndroid Build Coastguard Worker #include "ResourceTable.h"
9*d57664e9SAndroid Build Coastguard Worker #include "pseudolocalize.h"
10*d57664e9SAndroid Build Coastguard Worker
11*d57664e9SAndroid Build Coastguard Worker #include <utils/ByteOrder.h>
12*d57664e9SAndroid Build Coastguard Worker #include <errno.h>
13*d57664e9SAndroid Build Coastguard Worker #include <string.h>
14*d57664e9SAndroid Build Coastguard Worker
15*d57664e9SAndroid Build Coastguard Worker #ifndef _WIN32
16*d57664e9SAndroid Build Coastguard Worker #define O_BINARY 0
17*d57664e9SAndroid Build Coastguard Worker #endif
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
20*d57664e9SAndroid Build Coastguard Worker #if !defined(_WIN32)
21*d57664e9SAndroid Build Coastguard Worker # define STATUST(x) x
22*d57664e9SAndroid Build Coastguard Worker #else
23*d57664e9SAndroid Build Coastguard Worker # define STATUST(x) (status_t)x
24*d57664e9SAndroid Build Coastguard Worker #endif
25*d57664e9SAndroid Build Coastguard Worker
26*d57664e9SAndroid Build Coastguard Worker // Set to true for noisy debug output.
27*d57664e9SAndroid Build Coastguard Worker static const bool kIsDebug = false;
28*d57664e9SAndroid Build Coastguard Worker // Set to true for noisy debug output of parsing.
29*d57664e9SAndroid Build Coastguard Worker static const bool kIsDebugParse = false;
30*d57664e9SAndroid Build Coastguard Worker
31*d57664e9SAndroid Build Coastguard Worker #if PRINT_STRING_METRICS
32*d57664e9SAndroid Build Coastguard Worker static const bool kPrintStringMetrics = true;
33*d57664e9SAndroid Build Coastguard Worker #else
34*d57664e9SAndroid Build Coastguard Worker static const bool kPrintStringMetrics = false;
35*d57664e9SAndroid Build Coastguard Worker #endif
36*d57664e9SAndroid Build Coastguard Worker
37*d57664e9SAndroid Build Coastguard Worker const char* const RESOURCES_ROOT_NAMESPACE = "http://schemas.android.com/apk/res/";
38*d57664e9SAndroid Build Coastguard Worker const char* const RESOURCES_ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
39*d57664e9SAndroid Build Coastguard Worker const char* const RESOURCES_AUTO_PACKAGE_NAMESPACE = "http://schemas.android.com/apk/res-auto";
40*d57664e9SAndroid Build Coastguard Worker const char* const RESOURCES_ROOT_PRV_NAMESPACE = "http://schemas.android.com/apk/prv/res/";
41*d57664e9SAndroid Build Coastguard Worker
42*d57664e9SAndroid Build Coastguard Worker const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2";
43*d57664e9SAndroid Build Coastguard Worker const char* const ALLOWED_XLIFF_ELEMENTS[] = {
44*d57664e9SAndroid Build Coastguard Worker "bpt",
45*d57664e9SAndroid Build Coastguard Worker "ept",
46*d57664e9SAndroid Build Coastguard Worker "it",
47*d57664e9SAndroid Build Coastguard Worker "ph",
48*d57664e9SAndroid Build Coastguard Worker "g",
49*d57664e9SAndroid Build Coastguard Worker "bx",
50*d57664e9SAndroid Build Coastguard Worker "ex",
51*d57664e9SAndroid Build Coastguard Worker "x"
52*d57664e9SAndroid Build Coastguard Worker };
53*d57664e9SAndroid Build Coastguard Worker
isWhitespace(const char16_t * str)54*d57664e9SAndroid Build Coastguard Worker bool isWhitespace(const char16_t* str)
55*d57664e9SAndroid Build Coastguard Worker {
56*d57664e9SAndroid Build Coastguard Worker while (*str != 0 && *str < 128 && isspace(*str)) {
57*d57664e9SAndroid Build Coastguard Worker str++;
58*d57664e9SAndroid Build Coastguard Worker }
59*d57664e9SAndroid Build Coastguard Worker return *str == 0;
60*d57664e9SAndroid Build Coastguard Worker }
61*d57664e9SAndroid Build Coastguard Worker
62*d57664e9SAndroid Build Coastguard Worker static const String16 RESOURCES_PREFIX(RESOURCES_ROOT_NAMESPACE);
63*d57664e9SAndroid Build Coastguard Worker static const String16 RESOURCES_PREFIX_AUTO_PACKAGE(RESOURCES_AUTO_PACKAGE_NAMESPACE);
64*d57664e9SAndroid Build Coastguard Worker static const String16 RESOURCES_PRV_PREFIX(RESOURCES_ROOT_PRV_NAMESPACE);
65*d57664e9SAndroid Build Coastguard Worker static const String16 RESOURCES_TOOLS_NAMESPACE("http://schemas.android.com/tools");
66*d57664e9SAndroid Build Coastguard Worker
getNamespaceResourcePackage(const String16 & appPackage,const String16 & namespaceUri,bool * outIsPublic)67*d57664e9SAndroid Build Coastguard Worker String16 getNamespaceResourcePackage(const String16& appPackage, const String16& namespaceUri, bool* outIsPublic)
68*d57664e9SAndroid Build Coastguard Worker {
69*d57664e9SAndroid Build Coastguard Worker //printf("%s starts with %s?\n", String8(namespaceUri).c_str(),
70*d57664e9SAndroid Build Coastguard Worker // String8(RESOURCES_PREFIX).c_str());
71*d57664e9SAndroid Build Coastguard Worker size_t prefixSize;
72*d57664e9SAndroid Build Coastguard Worker bool isPublic = true;
73*d57664e9SAndroid Build Coastguard Worker if(namespaceUri.startsWith(RESOURCES_PREFIX_AUTO_PACKAGE)) {
74*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
75*d57664e9SAndroid Build Coastguard Worker printf("Using default application package: %s -> %s\n", String8(namespaceUri).c_str(),
76*d57664e9SAndroid Build Coastguard Worker String8(appPackage).c_str());
77*d57664e9SAndroid Build Coastguard Worker }
78*d57664e9SAndroid Build Coastguard Worker isPublic = true;
79*d57664e9SAndroid Build Coastguard Worker return appPackage;
80*d57664e9SAndroid Build Coastguard Worker } else if (namespaceUri.startsWith(RESOURCES_PREFIX)) {
81*d57664e9SAndroid Build Coastguard Worker prefixSize = RESOURCES_PREFIX.size();
82*d57664e9SAndroid Build Coastguard Worker } else if (namespaceUri.startsWith(RESOURCES_PRV_PREFIX)) {
83*d57664e9SAndroid Build Coastguard Worker isPublic = false;
84*d57664e9SAndroid Build Coastguard Worker prefixSize = RESOURCES_PRV_PREFIX.size();
85*d57664e9SAndroid Build Coastguard Worker } else {
86*d57664e9SAndroid Build Coastguard Worker if (outIsPublic) *outIsPublic = isPublic; // = true
87*d57664e9SAndroid Build Coastguard Worker return String16();
88*d57664e9SAndroid Build Coastguard Worker }
89*d57664e9SAndroid Build Coastguard Worker
90*d57664e9SAndroid Build Coastguard Worker //printf("YES!\n");
91*d57664e9SAndroid Build Coastguard Worker //printf("namespace: %s\n", String8(String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize)).c_str());
92*d57664e9SAndroid Build Coastguard Worker if (outIsPublic) *outIsPublic = isPublic;
93*d57664e9SAndroid Build Coastguard Worker return String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize);
94*d57664e9SAndroid Build Coastguard Worker }
95*d57664e9SAndroid Build Coastguard Worker
hasSubstitutionErrors(const char * fileName,ResXMLTree * inXml,const String16 & str16)96*d57664e9SAndroid Build Coastguard Worker status_t hasSubstitutionErrors(const char* fileName,
97*d57664e9SAndroid Build Coastguard Worker ResXMLTree* inXml,
98*d57664e9SAndroid Build Coastguard Worker const String16& str16)
99*d57664e9SAndroid Build Coastguard Worker {
100*d57664e9SAndroid Build Coastguard Worker const char16_t* str = str16.c_str();
101*d57664e9SAndroid Build Coastguard Worker const char16_t* p = str;
102*d57664e9SAndroid Build Coastguard Worker const char16_t* end = str + str16.size();
103*d57664e9SAndroid Build Coastguard Worker
104*d57664e9SAndroid Build Coastguard Worker bool nonpositional = false;
105*d57664e9SAndroid Build Coastguard Worker int argCount = 0;
106*d57664e9SAndroid Build Coastguard Worker
107*d57664e9SAndroid Build Coastguard Worker while (p < end) {
108*d57664e9SAndroid Build Coastguard Worker /*
109*d57664e9SAndroid Build Coastguard Worker * Look for the start of a Java-style substitution sequence.
110*d57664e9SAndroid Build Coastguard Worker */
111*d57664e9SAndroid Build Coastguard Worker if (*p == '%' && p + 1 < end) {
112*d57664e9SAndroid Build Coastguard Worker p++;
113*d57664e9SAndroid Build Coastguard Worker
114*d57664e9SAndroid Build Coastguard Worker // A literal percent sign represented by %%
115*d57664e9SAndroid Build Coastguard Worker if (*p == '%') {
116*d57664e9SAndroid Build Coastguard Worker p++;
117*d57664e9SAndroid Build Coastguard Worker continue;
118*d57664e9SAndroid Build Coastguard Worker }
119*d57664e9SAndroid Build Coastguard Worker
120*d57664e9SAndroid Build Coastguard Worker argCount++;
121*d57664e9SAndroid Build Coastguard Worker
122*d57664e9SAndroid Build Coastguard Worker if (*p >= '0' && *p <= '9') {
123*d57664e9SAndroid Build Coastguard Worker do {
124*d57664e9SAndroid Build Coastguard Worker p++;
125*d57664e9SAndroid Build Coastguard Worker } while (*p >= '0' && *p <= '9');
126*d57664e9SAndroid Build Coastguard Worker if (*p != '$') {
127*d57664e9SAndroid Build Coastguard Worker // This must be a size specification instead of position.
128*d57664e9SAndroid Build Coastguard Worker nonpositional = true;
129*d57664e9SAndroid Build Coastguard Worker }
130*d57664e9SAndroid Build Coastguard Worker } else if (*p == '<') {
131*d57664e9SAndroid Build Coastguard Worker // Reusing last argument; bad idea since it can be re-arranged.
132*d57664e9SAndroid Build Coastguard Worker nonpositional = true;
133*d57664e9SAndroid Build Coastguard Worker p++;
134*d57664e9SAndroid Build Coastguard Worker
135*d57664e9SAndroid Build Coastguard Worker // Optionally '$' can be specified at the end.
136*d57664e9SAndroid Build Coastguard Worker if (p < end && *p == '$') {
137*d57664e9SAndroid Build Coastguard Worker p++;
138*d57664e9SAndroid Build Coastguard Worker }
139*d57664e9SAndroid Build Coastguard Worker } else {
140*d57664e9SAndroid Build Coastguard Worker nonpositional = true;
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker
143*d57664e9SAndroid Build Coastguard Worker // Ignore flags and widths
144*d57664e9SAndroid Build Coastguard Worker while (p < end && (*p == '-' ||
145*d57664e9SAndroid Build Coastguard Worker *p == '#' ||
146*d57664e9SAndroid Build Coastguard Worker *p == '+' ||
147*d57664e9SAndroid Build Coastguard Worker *p == ' ' ||
148*d57664e9SAndroid Build Coastguard Worker *p == ',' ||
149*d57664e9SAndroid Build Coastguard Worker *p == '(' ||
150*d57664e9SAndroid Build Coastguard Worker (*p >= '0' && *p <= '9'))) {
151*d57664e9SAndroid Build Coastguard Worker p++;
152*d57664e9SAndroid Build Coastguard Worker }
153*d57664e9SAndroid Build Coastguard Worker
154*d57664e9SAndroid Build Coastguard Worker /*
155*d57664e9SAndroid Build Coastguard Worker * This is a shortcut to detect strings that are going to Time.format()
156*d57664e9SAndroid Build Coastguard Worker * instead of String.format()
157*d57664e9SAndroid Build Coastguard Worker *
158*d57664e9SAndroid Build Coastguard Worker * Comparison of String.format() and Time.format() args:
159*d57664e9SAndroid Build Coastguard Worker *
160*d57664e9SAndroid Build Coastguard Worker * String: ABC E GH ST X abcdefgh nost x
161*d57664e9SAndroid Build Coastguard Worker * Time: DEFGHKMS W Za d hkm s w yz
162*d57664e9SAndroid Build Coastguard Worker *
163*d57664e9SAndroid Build Coastguard Worker * Therefore we know it's definitely Time if we have:
164*d57664e9SAndroid Build Coastguard Worker * DFKMWZkmwyz
165*d57664e9SAndroid Build Coastguard Worker */
166*d57664e9SAndroid Build Coastguard Worker if (p < end) {
167*d57664e9SAndroid Build Coastguard Worker switch (*p) {
168*d57664e9SAndroid Build Coastguard Worker case 'D':
169*d57664e9SAndroid Build Coastguard Worker case 'F':
170*d57664e9SAndroid Build Coastguard Worker case 'K':
171*d57664e9SAndroid Build Coastguard Worker case 'M':
172*d57664e9SAndroid Build Coastguard Worker case 'W':
173*d57664e9SAndroid Build Coastguard Worker case 'Z':
174*d57664e9SAndroid Build Coastguard Worker case 'k':
175*d57664e9SAndroid Build Coastguard Worker case 'm':
176*d57664e9SAndroid Build Coastguard Worker case 'w':
177*d57664e9SAndroid Build Coastguard Worker case 'y':
178*d57664e9SAndroid Build Coastguard Worker case 'z':
179*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
180*d57664e9SAndroid Build Coastguard Worker }
181*d57664e9SAndroid Build Coastguard Worker }
182*d57664e9SAndroid Build Coastguard Worker }
183*d57664e9SAndroid Build Coastguard Worker
184*d57664e9SAndroid Build Coastguard Worker p++;
185*d57664e9SAndroid Build Coastguard Worker }
186*d57664e9SAndroid Build Coastguard Worker
187*d57664e9SAndroid Build Coastguard Worker /*
188*d57664e9SAndroid Build Coastguard Worker * If we have more than one substitution in this string and any of them
189*d57664e9SAndroid Build Coastguard Worker * are not in positional form, give the user an error.
190*d57664e9SAndroid Build Coastguard Worker */
191*d57664e9SAndroid Build Coastguard Worker if (argCount > 1 && nonpositional) {
192*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
193*d57664e9SAndroid Build Coastguard Worker "Multiple substitutions specified in non-positional format; "
194*d57664e9SAndroid Build Coastguard Worker "did you mean to add the formatted=\"false\" attribute?\n");
195*d57664e9SAndroid Build Coastguard Worker return NOT_ENOUGH_DATA;
196*d57664e9SAndroid Build Coastguard Worker }
197*d57664e9SAndroid Build Coastguard Worker
198*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
199*d57664e9SAndroid Build Coastguard Worker }
200*d57664e9SAndroid Build Coastguard Worker
parseStyledString(Bundle *,const char * fileName,ResXMLTree * inXml,const String16 & endTag,String16 * outString,Vector<StringPool::entry_style_span> * outSpans,bool isFormatted,PseudolocalizationMethod pseudolocalize)201*d57664e9SAndroid Build Coastguard Worker status_t parseStyledString(Bundle* /* bundle */,
202*d57664e9SAndroid Build Coastguard Worker const char* fileName,
203*d57664e9SAndroid Build Coastguard Worker ResXMLTree* inXml,
204*d57664e9SAndroid Build Coastguard Worker const String16& endTag,
205*d57664e9SAndroid Build Coastguard Worker String16* outString,
206*d57664e9SAndroid Build Coastguard Worker Vector<StringPool::entry_style_span>* outSpans,
207*d57664e9SAndroid Build Coastguard Worker bool isFormatted,
208*d57664e9SAndroid Build Coastguard Worker PseudolocalizationMethod pseudolocalize)
209*d57664e9SAndroid Build Coastguard Worker {
210*d57664e9SAndroid Build Coastguard Worker Vector<StringPool::entry_style_span> spanStack;
211*d57664e9SAndroid Build Coastguard Worker String16 curString;
212*d57664e9SAndroid Build Coastguard Worker String16 rawString;
213*d57664e9SAndroid Build Coastguard Worker Pseudolocalizer pseudo(pseudolocalize);
214*d57664e9SAndroid Build Coastguard Worker const char* errorMsg;
215*d57664e9SAndroid Build Coastguard Worker int xliffDepth = 0;
216*d57664e9SAndroid Build Coastguard Worker bool firstTime = true;
217*d57664e9SAndroid Build Coastguard Worker
218*d57664e9SAndroid Build Coastguard Worker size_t len;
219*d57664e9SAndroid Build Coastguard Worker ResXMLTree::event_code_t code;
220*d57664e9SAndroid Build Coastguard Worker curString.append(pseudo.start());
221*d57664e9SAndroid Build Coastguard Worker while ((code=inXml->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
222*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::TEXT) {
223*d57664e9SAndroid Build Coastguard Worker String16 text(inXml->getText(&len));
224*d57664e9SAndroid Build Coastguard Worker if (firstTime && text.size() > 0) {
225*d57664e9SAndroid Build Coastguard Worker firstTime = false;
226*d57664e9SAndroid Build Coastguard Worker if (text.c_str()[0] == '@') {
227*d57664e9SAndroid Build Coastguard Worker // If this is a resource reference, don't do the pseudoloc.
228*d57664e9SAndroid Build Coastguard Worker pseudolocalize = NO_PSEUDOLOCALIZATION;
229*d57664e9SAndroid Build Coastguard Worker pseudo.setMethod(pseudolocalize);
230*d57664e9SAndroid Build Coastguard Worker curString = String16();
231*d57664e9SAndroid Build Coastguard Worker }
232*d57664e9SAndroid Build Coastguard Worker }
233*d57664e9SAndroid Build Coastguard Worker if (xliffDepth == 0 && pseudolocalize > 0) {
234*d57664e9SAndroid Build Coastguard Worker curString.append(pseudo.text(text));
235*d57664e9SAndroid Build Coastguard Worker } else {
236*d57664e9SAndroid Build Coastguard Worker if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) {
237*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
238*d57664e9SAndroid Build Coastguard Worker } else {
239*d57664e9SAndroid Build Coastguard Worker curString.append(text);
240*d57664e9SAndroid Build Coastguard Worker }
241*d57664e9SAndroid Build Coastguard Worker }
242*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::START_TAG) {
243*d57664e9SAndroid Build Coastguard Worker const String16 element16(inXml->getElementName(&len));
244*d57664e9SAndroid Build Coastguard Worker const String8 element8(element16);
245*d57664e9SAndroid Build Coastguard Worker
246*d57664e9SAndroid Build Coastguard Worker size_t nslen;
247*d57664e9SAndroid Build Coastguard Worker const char16_t* ns = inXml->getElementNamespace(&nslen);
248*d57664e9SAndroid Build Coastguard Worker if (ns == NULL) {
249*d57664e9SAndroid Build Coastguard Worker ns = (const char16_t*)"\0\0";
250*d57664e9SAndroid Build Coastguard Worker nslen = 0;
251*d57664e9SAndroid Build Coastguard Worker }
252*d57664e9SAndroid Build Coastguard Worker const String8 nspace(String16(ns, nslen));
253*d57664e9SAndroid Build Coastguard Worker if (nspace == XLIFF_XMLNS) {
254*d57664e9SAndroid Build Coastguard Worker const int N = sizeof(ALLOWED_XLIFF_ELEMENTS)/sizeof(ALLOWED_XLIFF_ELEMENTS[0]);
255*d57664e9SAndroid Build Coastguard Worker for (int i=0; i<N; i++) {
256*d57664e9SAndroid Build Coastguard Worker if (element8 == ALLOWED_XLIFF_ELEMENTS[i]) {
257*d57664e9SAndroid Build Coastguard Worker xliffDepth++;
258*d57664e9SAndroid Build Coastguard Worker // in this case, treat it like it was just text, in other words, do nothing
259*d57664e9SAndroid Build Coastguard Worker // here and silently drop this element
260*d57664e9SAndroid Build Coastguard Worker goto moveon;
261*d57664e9SAndroid Build Coastguard Worker }
262*d57664e9SAndroid Build Coastguard Worker }
263*d57664e9SAndroid Build Coastguard Worker {
264*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
265*d57664e9SAndroid Build Coastguard Worker "Found unsupported XLIFF tag <%s>\n",
266*d57664e9SAndroid Build Coastguard Worker element8.c_str());
267*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
268*d57664e9SAndroid Build Coastguard Worker }
269*d57664e9SAndroid Build Coastguard Worker moveon:
270*d57664e9SAndroid Build Coastguard Worker continue;
271*d57664e9SAndroid Build Coastguard Worker }
272*d57664e9SAndroid Build Coastguard Worker
273*d57664e9SAndroid Build Coastguard Worker if (outSpans == NULL) {
274*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
275*d57664e9SAndroid Build Coastguard Worker "Found style tag <%s> where styles are not allowed\n", element8.c_str());
276*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
277*d57664e9SAndroid Build Coastguard Worker }
278*d57664e9SAndroid Build Coastguard Worker
279*d57664e9SAndroid Build Coastguard Worker if (!ResTable::collectString(outString, curString.c_str(),
280*d57664e9SAndroid Build Coastguard Worker curString.size(), false, &errorMsg, true)) {
281*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n",
282*d57664e9SAndroid Build Coastguard Worker errorMsg, String8(curString).c_str());
283*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
284*d57664e9SAndroid Build Coastguard Worker }
285*d57664e9SAndroid Build Coastguard Worker rawString.append(curString);
286*d57664e9SAndroid Build Coastguard Worker curString = String16();
287*d57664e9SAndroid Build Coastguard Worker
288*d57664e9SAndroid Build Coastguard Worker StringPool::entry_style_span span;
289*d57664e9SAndroid Build Coastguard Worker span.name = element16;
290*d57664e9SAndroid Build Coastguard Worker for (size_t ai=0; ai<inXml->getAttributeCount(); ai++) {
291*d57664e9SAndroid Build Coastguard Worker span.name.append(String16(";"));
292*d57664e9SAndroid Build Coastguard Worker const char16_t* str = inXml->getAttributeName(ai, &len);
293*d57664e9SAndroid Build Coastguard Worker span.name.append(str, len);
294*d57664e9SAndroid Build Coastguard Worker span.name.append(String16("="));
295*d57664e9SAndroid Build Coastguard Worker str = inXml->getAttributeStringValue(ai, &len);
296*d57664e9SAndroid Build Coastguard Worker span.name.append(str, len);
297*d57664e9SAndroid Build Coastguard Worker }
298*d57664e9SAndroid Build Coastguard Worker //printf("Span: %s\n", String8(span.name).c_str());
299*d57664e9SAndroid Build Coastguard Worker span.span.firstChar = span.span.lastChar = outString->size();
300*d57664e9SAndroid Build Coastguard Worker spanStack.push(span);
301*d57664e9SAndroid Build Coastguard Worker
302*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::END_TAG) {
303*d57664e9SAndroid Build Coastguard Worker size_t nslen;
304*d57664e9SAndroid Build Coastguard Worker const char16_t* ns = inXml->getElementNamespace(&nslen);
305*d57664e9SAndroid Build Coastguard Worker if (ns == NULL) {
306*d57664e9SAndroid Build Coastguard Worker ns = (const char16_t*)"\0\0";
307*d57664e9SAndroid Build Coastguard Worker nslen = 0;
308*d57664e9SAndroid Build Coastguard Worker }
309*d57664e9SAndroid Build Coastguard Worker const String8 nspace(String16(ns, nslen));
310*d57664e9SAndroid Build Coastguard Worker if (nspace == XLIFF_XMLNS) {
311*d57664e9SAndroid Build Coastguard Worker xliffDepth--;
312*d57664e9SAndroid Build Coastguard Worker continue;
313*d57664e9SAndroid Build Coastguard Worker }
314*d57664e9SAndroid Build Coastguard Worker if (!ResTable::collectString(outString, curString.c_str(),
315*d57664e9SAndroid Build Coastguard Worker curString.size(), false, &errorMsg, true)) {
316*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n",
317*d57664e9SAndroid Build Coastguard Worker errorMsg, String8(curString).c_str());
318*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
319*d57664e9SAndroid Build Coastguard Worker }
320*d57664e9SAndroid Build Coastguard Worker rawString.append(curString);
321*d57664e9SAndroid Build Coastguard Worker curString = String16();
322*d57664e9SAndroid Build Coastguard Worker
323*d57664e9SAndroid Build Coastguard Worker if (spanStack.size() == 0) {
324*d57664e9SAndroid Build Coastguard Worker if (strcmp16(inXml->getElementName(&len), endTag.c_str()) != 0) {
325*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
326*d57664e9SAndroid Build Coastguard Worker "Found tag %s where <%s> close is expected\n",
327*d57664e9SAndroid Build Coastguard Worker String8(inXml->getElementName(&len)).c_str(),
328*d57664e9SAndroid Build Coastguard Worker String8(endTag).c_str());
329*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
330*d57664e9SAndroid Build Coastguard Worker }
331*d57664e9SAndroid Build Coastguard Worker break;
332*d57664e9SAndroid Build Coastguard Worker }
333*d57664e9SAndroid Build Coastguard Worker StringPool::entry_style_span span = spanStack.top();
334*d57664e9SAndroid Build Coastguard Worker String16 spanTag;
335*d57664e9SAndroid Build Coastguard Worker ssize_t semi = span.name.findFirst(';');
336*d57664e9SAndroid Build Coastguard Worker if (semi >= 0) {
337*d57664e9SAndroid Build Coastguard Worker spanTag = String16(span.name.c_str(), semi);
338*d57664e9SAndroid Build Coastguard Worker } else {
339*d57664e9SAndroid Build Coastguard Worker spanTag = span.name;
340*d57664e9SAndroid Build Coastguard Worker }
341*d57664e9SAndroid Build Coastguard Worker if (strcmp16(inXml->getElementName(&len), spanTag.c_str()) != 0) {
342*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
343*d57664e9SAndroid Build Coastguard Worker "Found close tag %s where close tag %s is expected\n",
344*d57664e9SAndroid Build Coastguard Worker String8(inXml->getElementName(&len)).c_str(),
345*d57664e9SAndroid Build Coastguard Worker String8(spanTag).c_str());
346*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
347*d57664e9SAndroid Build Coastguard Worker }
348*d57664e9SAndroid Build Coastguard Worker bool empty = true;
349*d57664e9SAndroid Build Coastguard Worker if (outString->size() > 0) {
350*d57664e9SAndroid Build Coastguard Worker span.span.lastChar = outString->size()-1;
351*d57664e9SAndroid Build Coastguard Worker if (span.span.lastChar >= span.span.firstChar) {
352*d57664e9SAndroid Build Coastguard Worker empty = false;
353*d57664e9SAndroid Build Coastguard Worker outSpans->add(span);
354*d57664e9SAndroid Build Coastguard Worker }
355*d57664e9SAndroid Build Coastguard Worker }
356*d57664e9SAndroid Build Coastguard Worker spanStack.pop();
357*d57664e9SAndroid Build Coastguard Worker
358*d57664e9SAndroid Build Coastguard Worker /*
359*d57664e9SAndroid Build Coastguard Worker * This warning seems to be just an irritation to most people,
360*d57664e9SAndroid Build Coastguard Worker * since it is typically introduced by translators who then never
361*d57664e9SAndroid Build Coastguard Worker * see the warning.
362*d57664e9SAndroid Build Coastguard Worker */
363*d57664e9SAndroid Build Coastguard Worker if (0 && empty) {
364*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n",
365*d57664e9SAndroid Build Coastguard Worker fileName, inXml->getLineNumber(),
366*d57664e9SAndroid Build Coastguard Worker String8(spanTag).c_str(), String8(*outString).c_str());
367*d57664e9SAndroid Build Coastguard Worker
368*d57664e9SAndroid Build Coastguard Worker }
369*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::START_NAMESPACE) {
370*d57664e9SAndroid Build Coastguard Worker // nothing
371*d57664e9SAndroid Build Coastguard Worker }
372*d57664e9SAndroid Build Coastguard Worker }
373*d57664e9SAndroid Build Coastguard Worker
374*d57664e9SAndroid Build Coastguard Worker curString.append(pseudo.end());
375*d57664e9SAndroid Build Coastguard Worker
376*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::BAD_DOCUMENT) {
377*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
378*d57664e9SAndroid Build Coastguard Worker "Error parsing XML\n");
379*d57664e9SAndroid Build Coastguard Worker }
380*d57664e9SAndroid Build Coastguard Worker
381*d57664e9SAndroid Build Coastguard Worker if (outSpans != NULL && outSpans->size() > 0) {
382*d57664e9SAndroid Build Coastguard Worker if (curString.size() > 0) {
383*d57664e9SAndroid Build Coastguard Worker if (!ResTable::collectString(outString, curString.c_str(),
384*d57664e9SAndroid Build Coastguard Worker curString.size(), false, &errorMsg, true)) {
385*d57664e9SAndroid Build Coastguard Worker SourcePos(String8(fileName), inXml->getLineNumber()).error(
386*d57664e9SAndroid Build Coastguard Worker "%s (in %s)\n",
387*d57664e9SAndroid Build Coastguard Worker errorMsg, String8(curString).c_str());
388*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
389*d57664e9SAndroid Build Coastguard Worker }
390*d57664e9SAndroid Build Coastguard Worker }
391*d57664e9SAndroid Build Coastguard Worker } else {
392*d57664e9SAndroid Build Coastguard Worker // There is no style information, so string processing will happen
393*d57664e9SAndroid Build Coastguard Worker // later as part of the overall type conversion. Return to the
394*d57664e9SAndroid Build Coastguard Worker // client the raw unprocessed text.
395*d57664e9SAndroid Build Coastguard Worker rawString.append(curString);
396*d57664e9SAndroid Build Coastguard Worker *outString = rawString;
397*d57664e9SAndroid Build Coastguard Worker }
398*d57664e9SAndroid Build Coastguard Worker
399*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
400*d57664e9SAndroid Build Coastguard Worker }
401*d57664e9SAndroid Build Coastguard Worker
402*d57664e9SAndroid Build Coastguard Worker struct namespace_entry {
403*d57664e9SAndroid Build Coastguard Worker String8 prefix;
404*d57664e9SAndroid Build Coastguard Worker String8 uri;
405*d57664e9SAndroid Build Coastguard Worker };
406*d57664e9SAndroid Build Coastguard Worker
make_prefix(int depth)407*d57664e9SAndroid Build Coastguard Worker static String8 make_prefix(int depth)
408*d57664e9SAndroid Build Coastguard Worker {
409*d57664e9SAndroid Build Coastguard Worker String8 prefix;
410*d57664e9SAndroid Build Coastguard Worker int i;
411*d57664e9SAndroid Build Coastguard Worker for (i=0; i<depth; i++) {
412*d57664e9SAndroid Build Coastguard Worker prefix.append(" ");
413*d57664e9SAndroid Build Coastguard Worker }
414*d57664e9SAndroid Build Coastguard Worker return prefix;
415*d57664e9SAndroid Build Coastguard Worker }
416*d57664e9SAndroid Build Coastguard Worker
build_namespace(const Vector<namespace_entry> & namespaces,const char16_t * ns)417*d57664e9SAndroid Build Coastguard Worker static String8 build_namespace(const Vector<namespace_entry>& namespaces,
418*d57664e9SAndroid Build Coastguard Worker const char16_t* ns)
419*d57664e9SAndroid Build Coastguard Worker {
420*d57664e9SAndroid Build Coastguard Worker String8 str;
421*d57664e9SAndroid Build Coastguard Worker if (ns != NULL) {
422*d57664e9SAndroid Build Coastguard Worker str = String8(ns);
423*d57664e9SAndroid Build Coastguard Worker const size_t N = namespaces.size();
424*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
425*d57664e9SAndroid Build Coastguard Worker const namespace_entry& ne = namespaces.itemAt(i);
426*d57664e9SAndroid Build Coastguard Worker if (ne.uri == str) {
427*d57664e9SAndroid Build Coastguard Worker str = ne.prefix;
428*d57664e9SAndroid Build Coastguard Worker break;
429*d57664e9SAndroid Build Coastguard Worker }
430*d57664e9SAndroid Build Coastguard Worker }
431*d57664e9SAndroid Build Coastguard Worker str.append(":");
432*d57664e9SAndroid Build Coastguard Worker }
433*d57664e9SAndroid Build Coastguard Worker return str;
434*d57664e9SAndroid Build Coastguard Worker }
435*d57664e9SAndroid Build Coastguard Worker
printXMLBlock(ResXMLTree * block)436*d57664e9SAndroid Build Coastguard Worker void printXMLBlock(ResXMLTree* block)
437*d57664e9SAndroid Build Coastguard Worker {
438*d57664e9SAndroid Build Coastguard Worker block->restart();
439*d57664e9SAndroid Build Coastguard Worker
440*d57664e9SAndroid Build Coastguard Worker Vector<namespace_entry> namespaces;
441*d57664e9SAndroid Build Coastguard Worker
442*d57664e9SAndroid Build Coastguard Worker ResXMLTree::event_code_t code;
443*d57664e9SAndroid Build Coastguard Worker int depth = 0;
444*d57664e9SAndroid Build Coastguard Worker while ((code=block->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
445*d57664e9SAndroid Build Coastguard Worker String8 prefix = make_prefix(depth);
446*d57664e9SAndroid Build Coastguard Worker int i;
447*d57664e9SAndroid Build Coastguard Worker if (code == ResXMLTree::START_TAG) {
448*d57664e9SAndroid Build Coastguard Worker size_t len;
449*d57664e9SAndroid Build Coastguard Worker const char16_t* ns16 = block->getElementNamespace(&len);
450*d57664e9SAndroid Build Coastguard Worker String8 elemNs = build_namespace(namespaces, ns16);
451*d57664e9SAndroid Build Coastguard Worker const char16_t* com16 = block->getComment(&len);
452*d57664e9SAndroid Build Coastguard Worker if (com16) {
453*d57664e9SAndroid Build Coastguard Worker printf("%s <!-- %s -->\n", prefix.c_str(), String8(com16).c_str());
454*d57664e9SAndroid Build Coastguard Worker }
455*d57664e9SAndroid Build Coastguard Worker printf("%sE: %s%s (line=%d)\n", prefix.c_str(), elemNs.c_str(),
456*d57664e9SAndroid Build Coastguard Worker String8(block->getElementName(&len)).c_str(),
457*d57664e9SAndroid Build Coastguard Worker block->getLineNumber());
458*d57664e9SAndroid Build Coastguard Worker int N = block->getAttributeCount();
459*d57664e9SAndroid Build Coastguard Worker depth++;
460*d57664e9SAndroid Build Coastguard Worker prefix = make_prefix(depth);
461*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
462*d57664e9SAndroid Build Coastguard Worker uint32_t res = block->getAttributeNameResID(i);
463*d57664e9SAndroid Build Coastguard Worker ns16 = block->getAttributeNamespace(i, &len);
464*d57664e9SAndroid Build Coastguard Worker String8 ns = build_namespace(namespaces, ns16);
465*d57664e9SAndroid Build Coastguard Worker String8 name(block->getAttributeName(i, &len));
466*d57664e9SAndroid Build Coastguard Worker printf("%sA: ", prefix.c_str());
467*d57664e9SAndroid Build Coastguard Worker if (res) {
468*d57664e9SAndroid Build Coastguard Worker printf("%s%s(0x%08x)", ns.c_str(), name.c_str(), res);
469*d57664e9SAndroid Build Coastguard Worker } else {
470*d57664e9SAndroid Build Coastguard Worker printf("%s%s", ns.c_str(), name.c_str());
471*d57664e9SAndroid Build Coastguard Worker }
472*d57664e9SAndroid Build Coastguard Worker Res_value value;
473*d57664e9SAndroid Build Coastguard Worker block->getAttributeValue(i, &value);
474*d57664e9SAndroid Build Coastguard Worker if (value.dataType == Res_value::TYPE_NULL) {
475*d57664e9SAndroid Build Coastguard Worker printf("=(null)");
476*d57664e9SAndroid Build Coastguard Worker } else if (value.dataType == Res_value::TYPE_REFERENCE) {
477*d57664e9SAndroid Build Coastguard Worker printf("=@0x%08x", (int)value.data);
478*d57664e9SAndroid Build Coastguard Worker } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
479*d57664e9SAndroid Build Coastguard Worker printf("=?0x%08x", (int)value.data);
480*d57664e9SAndroid Build Coastguard Worker } else if (value.dataType == Res_value::TYPE_STRING) {
481*d57664e9SAndroid Build Coastguard Worker printf("=\"%s\"",
482*d57664e9SAndroid Build Coastguard Worker ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i,
483*d57664e9SAndroid Build Coastguard Worker &len)).c_str()).c_str());
484*d57664e9SAndroid Build Coastguard Worker } else {
485*d57664e9SAndroid Build Coastguard Worker printf("=(type 0x%x)0x%x", (int)value.dataType, (int)value.data);
486*d57664e9SAndroid Build Coastguard Worker }
487*d57664e9SAndroid Build Coastguard Worker const char16_t* val = block->getAttributeStringValue(i, &len);
488*d57664e9SAndroid Build Coastguard Worker if (val != NULL) {
489*d57664e9SAndroid Build Coastguard Worker printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).c_str()).
490*d57664e9SAndroid Build Coastguard Worker c_str());
491*d57664e9SAndroid Build Coastguard Worker }
492*d57664e9SAndroid Build Coastguard Worker printf("\n");
493*d57664e9SAndroid Build Coastguard Worker }
494*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::END_TAG) {
495*d57664e9SAndroid Build Coastguard Worker // Invalid tag nesting can be misused to break the parsing
496*d57664e9SAndroid Build Coastguard Worker // code below. Break if detected.
497*d57664e9SAndroid Build Coastguard Worker if (--depth < 0) {
498*d57664e9SAndroid Build Coastguard Worker printf("***BAD DEPTH in XMLBlock: %d\n", depth);
499*d57664e9SAndroid Build Coastguard Worker break;
500*d57664e9SAndroid Build Coastguard Worker }
501*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::START_NAMESPACE) {
502*d57664e9SAndroid Build Coastguard Worker namespace_entry ns;
503*d57664e9SAndroid Build Coastguard Worker size_t len;
504*d57664e9SAndroid Build Coastguard Worker const char16_t* prefix16 = block->getNamespacePrefix(&len);
505*d57664e9SAndroid Build Coastguard Worker if (prefix16) {
506*d57664e9SAndroid Build Coastguard Worker ns.prefix = String8(prefix16);
507*d57664e9SAndroid Build Coastguard Worker } else {
508*d57664e9SAndroid Build Coastguard Worker ns.prefix = "<DEF>";
509*d57664e9SAndroid Build Coastguard Worker }
510*d57664e9SAndroid Build Coastguard Worker ns.uri = String8(block->getNamespaceUri(&len));
511*d57664e9SAndroid Build Coastguard Worker namespaces.push(ns);
512*d57664e9SAndroid Build Coastguard Worker printf("%sN: %s=%s\n", prefix.c_str(), ns.prefix.c_str(),
513*d57664e9SAndroid Build Coastguard Worker ns.uri.c_str());
514*d57664e9SAndroid Build Coastguard Worker depth++;
515*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::END_NAMESPACE) {
516*d57664e9SAndroid Build Coastguard Worker if (--depth < 0) {
517*d57664e9SAndroid Build Coastguard Worker printf("***BAD DEPTH in XMLBlock: %d\n", depth);
518*d57664e9SAndroid Build Coastguard Worker break;
519*d57664e9SAndroid Build Coastguard Worker }
520*d57664e9SAndroid Build Coastguard Worker const namespace_entry& ns = namespaces.top();
521*d57664e9SAndroid Build Coastguard Worker size_t len;
522*d57664e9SAndroid Build Coastguard Worker const char16_t* prefix16 = block->getNamespacePrefix(&len);
523*d57664e9SAndroid Build Coastguard Worker String8 pr;
524*d57664e9SAndroid Build Coastguard Worker if (prefix16) {
525*d57664e9SAndroid Build Coastguard Worker pr = String8(prefix16);
526*d57664e9SAndroid Build Coastguard Worker } else {
527*d57664e9SAndroid Build Coastguard Worker pr = "<DEF>";
528*d57664e9SAndroid Build Coastguard Worker }
529*d57664e9SAndroid Build Coastguard Worker if (ns.prefix != pr) {
530*d57664e9SAndroid Build Coastguard Worker prefix = make_prefix(depth);
531*d57664e9SAndroid Build Coastguard Worker printf("%s*** BAD END NS PREFIX: found=%s, expected=%s\n",
532*d57664e9SAndroid Build Coastguard Worker prefix.c_str(), pr.c_str(), ns.prefix.c_str());
533*d57664e9SAndroid Build Coastguard Worker }
534*d57664e9SAndroid Build Coastguard Worker String8 uri = String8(block->getNamespaceUri(&len));
535*d57664e9SAndroid Build Coastguard Worker if (ns.uri != uri) {
536*d57664e9SAndroid Build Coastguard Worker prefix = make_prefix(depth);
537*d57664e9SAndroid Build Coastguard Worker printf("%s *** BAD END NS URI: found=%s, expected=%s\n",
538*d57664e9SAndroid Build Coastguard Worker prefix.c_str(), uri.c_str(), ns.uri.c_str());
539*d57664e9SAndroid Build Coastguard Worker }
540*d57664e9SAndroid Build Coastguard Worker namespaces.pop();
541*d57664e9SAndroid Build Coastguard Worker } else if (code == ResXMLTree::TEXT) {
542*d57664e9SAndroid Build Coastguard Worker size_t len;
543*d57664e9SAndroid Build Coastguard Worker printf("%sC: \"%s\"\n", prefix.c_str(),
544*d57664e9SAndroid Build Coastguard Worker ResTable::normalizeForOutput(String8(block->getText(&len)).c_str()).c_str());
545*d57664e9SAndroid Build Coastguard Worker }
546*d57664e9SAndroid Build Coastguard Worker }
547*d57664e9SAndroid Build Coastguard Worker
548*d57664e9SAndroid Build Coastguard Worker block->restart();
549*d57664e9SAndroid Build Coastguard Worker }
550*d57664e9SAndroid Build Coastguard Worker
parseXMLResource(const sp<AaptFile> & file,ResXMLTree * outTree,bool stripAll,bool keepComments,const char ** cDataTags)551*d57664e9SAndroid Build Coastguard Worker status_t parseXMLResource(const sp<AaptFile>& file, ResXMLTree* outTree,
552*d57664e9SAndroid Build Coastguard Worker bool stripAll, bool keepComments,
553*d57664e9SAndroid Build Coastguard Worker const char** cDataTags)
554*d57664e9SAndroid Build Coastguard Worker {
555*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> root = XMLNode::parse(file);
556*d57664e9SAndroid Build Coastguard Worker if (root == NULL) {
557*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
558*d57664e9SAndroid Build Coastguard Worker }
559*d57664e9SAndroid Build Coastguard Worker root->removeWhitespace(stripAll, cDataTags);
560*d57664e9SAndroid Build Coastguard Worker
561*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
562*d57664e9SAndroid Build Coastguard Worker printf("Input XML from %s:\n", file->getPrintableSource().c_str());
563*d57664e9SAndroid Build Coastguard Worker root->print();
564*d57664e9SAndroid Build Coastguard Worker }
565*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> rsc = new AaptFile(String8(), AaptGroupEntry(), String8());
566*d57664e9SAndroid Build Coastguard Worker status_t err = root->flatten(rsc, !keepComments, false);
567*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
568*d57664e9SAndroid Build Coastguard Worker return err;
569*d57664e9SAndroid Build Coastguard Worker }
570*d57664e9SAndroid Build Coastguard Worker err = outTree->setTo(rsc->getData(), rsc->getSize(), true);
571*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
572*d57664e9SAndroid Build Coastguard Worker return err;
573*d57664e9SAndroid Build Coastguard Worker }
574*d57664e9SAndroid Build Coastguard Worker
575*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
576*d57664e9SAndroid Build Coastguard Worker printf("Output XML:\n");
577*d57664e9SAndroid Build Coastguard Worker printXMLBlock(outTree);
578*d57664e9SAndroid Build Coastguard Worker }
579*d57664e9SAndroid Build Coastguard Worker
580*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
581*d57664e9SAndroid Build Coastguard Worker }
582*d57664e9SAndroid Build Coastguard Worker
parse(const sp<AaptFile> & file)583*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> XMLNode::parse(const sp<AaptFile>& file)
584*d57664e9SAndroid Build Coastguard Worker {
585*d57664e9SAndroid Build Coastguard Worker char buf[16384];
586*d57664e9SAndroid Build Coastguard Worker int fd = open(file->getSourceFile().c_str(), O_RDONLY | O_BINARY);
587*d57664e9SAndroid Build Coastguard Worker if (fd < 0) {
588*d57664e9SAndroid Build Coastguard Worker SourcePos(file->getSourceFile(), -1).error("Unable to open file for read: %s",
589*d57664e9SAndroid Build Coastguard Worker strerror(errno));
590*d57664e9SAndroid Build Coastguard Worker return NULL;
591*d57664e9SAndroid Build Coastguard Worker }
592*d57664e9SAndroid Build Coastguard Worker
593*d57664e9SAndroid Build Coastguard Worker XML_Parser parser = XML_ParserCreateNS(NULL, 1);
594*d57664e9SAndroid Build Coastguard Worker ParseState state;
595*d57664e9SAndroid Build Coastguard Worker state.filename = file->getPrintableSource();
596*d57664e9SAndroid Build Coastguard Worker state.parser = parser;
597*d57664e9SAndroid Build Coastguard Worker XML_SetUserData(parser, &state);
598*d57664e9SAndroid Build Coastguard Worker XML_SetElementHandler(parser, startElement, endElement);
599*d57664e9SAndroid Build Coastguard Worker XML_SetNamespaceDeclHandler(parser, startNamespace, endNamespace);
600*d57664e9SAndroid Build Coastguard Worker XML_SetCharacterDataHandler(parser, characterData);
601*d57664e9SAndroid Build Coastguard Worker XML_SetCommentHandler(parser, commentData);
602*d57664e9SAndroid Build Coastguard Worker
603*d57664e9SAndroid Build Coastguard Worker ssize_t len;
604*d57664e9SAndroid Build Coastguard Worker bool done;
605*d57664e9SAndroid Build Coastguard Worker do {
606*d57664e9SAndroid Build Coastguard Worker len = read(fd, buf, sizeof(buf));
607*d57664e9SAndroid Build Coastguard Worker done = len < (ssize_t)sizeof(buf);
608*d57664e9SAndroid Build Coastguard Worker if (len < 0) {
609*d57664e9SAndroid Build Coastguard Worker SourcePos(file->getSourceFile(), -1).error("Error reading file: %s\n", strerror(errno));
610*d57664e9SAndroid Build Coastguard Worker close(fd);
611*d57664e9SAndroid Build Coastguard Worker return NULL;
612*d57664e9SAndroid Build Coastguard Worker }
613*d57664e9SAndroid Build Coastguard Worker if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
614*d57664e9SAndroid Build Coastguard Worker SourcePos(file->getSourceFile(), (int)XML_GetCurrentLineNumber(parser)).error(
615*d57664e9SAndroid Build Coastguard Worker "Error parsing XML: %s\n", XML_ErrorString(XML_GetErrorCode(parser)));
616*d57664e9SAndroid Build Coastguard Worker close(fd);
617*d57664e9SAndroid Build Coastguard Worker return NULL;
618*d57664e9SAndroid Build Coastguard Worker }
619*d57664e9SAndroid Build Coastguard Worker } while (!done);
620*d57664e9SAndroid Build Coastguard Worker
621*d57664e9SAndroid Build Coastguard Worker XML_ParserFree(parser);
622*d57664e9SAndroid Build Coastguard Worker if (state.root == NULL) {
623*d57664e9SAndroid Build Coastguard Worker SourcePos(file->getSourceFile(), -1).error("No XML data generated when parsing");
624*d57664e9SAndroid Build Coastguard Worker }
625*d57664e9SAndroid Build Coastguard Worker close(fd);
626*d57664e9SAndroid Build Coastguard Worker return state.root;
627*d57664e9SAndroid Build Coastguard Worker }
628*d57664e9SAndroid Build Coastguard Worker
XMLNode()629*d57664e9SAndroid Build Coastguard Worker XMLNode::XMLNode()
630*d57664e9SAndroid Build Coastguard Worker : mNextAttributeIndex(0x80000000)
631*d57664e9SAndroid Build Coastguard Worker , mStartLineNumber(0)
632*d57664e9SAndroid Build Coastguard Worker , mEndLineNumber(0)
633*d57664e9SAndroid Build Coastguard Worker , mUTF8(false) {}
634*d57664e9SAndroid Build Coastguard Worker
XMLNode(const String8 & filename,const String16 & s1,const String16 & s2,bool isNamespace)635*d57664e9SAndroid Build Coastguard Worker XMLNode::XMLNode(const String8& filename, const String16& s1, const String16& s2, bool isNamespace)
636*d57664e9SAndroid Build Coastguard Worker : mNextAttributeIndex(0x80000000)
637*d57664e9SAndroid Build Coastguard Worker , mFilename(filename)
638*d57664e9SAndroid Build Coastguard Worker , mStartLineNumber(0)
639*d57664e9SAndroid Build Coastguard Worker , mEndLineNumber(0)
640*d57664e9SAndroid Build Coastguard Worker , mUTF8(false)
641*d57664e9SAndroid Build Coastguard Worker {
642*d57664e9SAndroid Build Coastguard Worker if (isNamespace) {
643*d57664e9SAndroid Build Coastguard Worker mNamespacePrefix = s1;
644*d57664e9SAndroid Build Coastguard Worker mNamespaceUri = s2;
645*d57664e9SAndroid Build Coastguard Worker } else {
646*d57664e9SAndroid Build Coastguard Worker mNamespaceUri = s1;
647*d57664e9SAndroid Build Coastguard Worker mElementName = s2;
648*d57664e9SAndroid Build Coastguard Worker }
649*d57664e9SAndroid Build Coastguard Worker }
650*d57664e9SAndroid Build Coastguard Worker
XMLNode(const String8 & filename)651*d57664e9SAndroid Build Coastguard Worker XMLNode::XMLNode(const String8& filename)
652*d57664e9SAndroid Build Coastguard Worker : mFilename(filename)
653*d57664e9SAndroid Build Coastguard Worker {
654*d57664e9SAndroid Build Coastguard Worker memset(&mCharsValue, 0, sizeof(mCharsValue));
655*d57664e9SAndroid Build Coastguard Worker }
656*d57664e9SAndroid Build Coastguard Worker
getType() const657*d57664e9SAndroid Build Coastguard Worker XMLNode::type XMLNode::getType() const
658*d57664e9SAndroid Build Coastguard Worker {
659*d57664e9SAndroid Build Coastguard Worker if (mElementName.size() != 0) {
660*d57664e9SAndroid Build Coastguard Worker return TYPE_ELEMENT;
661*d57664e9SAndroid Build Coastguard Worker }
662*d57664e9SAndroid Build Coastguard Worker if (mNamespaceUri.size() != 0) {
663*d57664e9SAndroid Build Coastguard Worker return TYPE_NAMESPACE;
664*d57664e9SAndroid Build Coastguard Worker }
665*d57664e9SAndroid Build Coastguard Worker return TYPE_CDATA;
666*d57664e9SAndroid Build Coastguard Worker }
667*d57664e9SAndroid Build Coastguard Worker
getNamespacePrefix() const668*d57664e9SAndroid Build Coastguard Worker const String16& XMLNode::getNamespacePrefix() const
669*d57664e9SAndroid Build Coastguard Worker {
670*d57664e9SAndroid Build Coastguard Worker return mNamespacePrefix;
671*d57664e9SAndroid Build Coastguard Worker }
672*d57664e9SAndroid Build Coastguard Worker
getNamespaceUri() const673*d57664e9SAndroid Build Coastguard Worker const String16& XMLNode::getNamespaceUri() const
674*d57664e9SAndroid Build Coastguard Worker {
675*d57664e9SAndroid Build Coastguard Worker return mNamespaceUri;
676*d57664e9SAndroid Build Coastguard Worker }
677*d57664e9SAndroid Build Coastguard Worker
getElementNamespace() const678*d57664e9SAndroid Build Coastguard Worker const String16& XMLNode::getElementNamespace() const
679*d57664e9SAndroid Build Coastguard Worker {
680*d57664e9SAndroid Build Coastguard Worker return mNamespaceUri;
681*d57664e9SAndroid Build Coastguard Worker }
682*d57664e9SAndroid Build Coastguard Worker
getElementName() const683*d57664e9SAndroid Build Coastguard Worker const String16& XMLNode::getElementName() const
684*d57664e9SAndroid Build Coastguard Worker {
685*d57664e9SAndroid Build Coastguard Worker return mElementName;
686*d57664e9SAndroid Build Coastguard Worker }
687*d57664e9SAndroid Build Coastguard Worker
getChildren() const688*d57664e9SAndroid Build Coastguard Worker const Vector<sp<XMLNode> >& XMLNode::getChildren() const
689*d57664e9SAndroid Build Coastguard Worker {
690*d57664e9SAndroid Build Coastguard Worker return mChildren;
691*d57664e9SAndroid Build Coastguard Worker }
692*d57664e9SAndroid Build Coastguard Worker
693*d57664e9SAndroid Build Coastguard Worker
getChildren()694*d57664e9SAndroid Build Coastguard Worker Vector<sp<XMLNode> >& XMLNode::getChildren()
695*d57664e9SAndroid Build Coastguard Worker {
696*d57664e9SAndroid Build Coastguard Worker return mChildren;
697*d57664e9SAndroid Build Coastguard Worker }
698*d57664e9SAndroid Build Coastguard Worker
getFilename() const699*d57664e9SAndroid Build Coastguard Worker const String8& XMLNode::getFilename() const
700*d57664e9SAndroid Build Coastguard Worker {
701*d57664e9SAndroid Build Coastguard Worker return mFilename;
702*d57664e9SAndroid Build Coastguard Worker }
703*d57664e9SAndroid Build Coastguard Worker
704*d57664e9SAndroid Build Coastguard Worker const Vector<XMLNode::attribute_entry>&
getAttributes() const705*d57664e9SAndroid Build Coastguard Worker XMLNode::getAttributes() const
706*d57664e9SAndroid Build Coastguard Worker {
707*d57664e9SAndroid Build Coastguard Worker return mAttributes;
708*d57664e9SAndroid Build Coastguard Worker }
709*d57664e9SAndroid Build Coastguard Worker
getAttribute(const String16 & ns,const String16 & name) const710*d57664e9SAndroid Build Coastguard Worker const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns,
711*d57664e9SAndroid Build Coastguard Worker const String16& name) const
712*d57664e9SAndroid Build Coastguard Worker {
713*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<mAttributes.size(); i++) {
714*d57664e9SAndroid Build Coastguard Worker const attribute_entry& ae(mAttributes.itemAt(i));
715*d57664e9SAndroid Build Coastguard Worker if (ae.ns == ns && ae.name == name) {
716*d57664e9SAndroid Build Coastguard Worker return &ae;
717*d57664e9SAndroid Build Coastguard Worker }
718*d57664e9SAndroid Build Coastguard Worker }
719*d57664e9SAndroid Build Coastguard Worker
720*d57664e9SAndroid Build Coastguard Worker return NULL;
721*d57664e9SAndroid Build Coastguard Worker }
722*d57664e9SAndroid Build Coastguard Worker
removeAttribute(const String16 & ns,const String16 & name)723*d57664e9SAndroid Build Coastguard Worker bool XMLNode::removeAttribute(const String16& ns, const String16& name)
724*d57664e9SAndroid Build Coastguard Worker {
725*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < mAttributes.size(); i++) {
726*d57664e9SAndroid Build Coastguard Worker const attribute_entry& ae(mAttributes.itemAt(i));
727*d57664e9SAndroid Build Coastguard Worker if (ae.ns == ns && ae.name == name) {
728*d57664e9SAndroid Build Coastguard Worker removeAttribute(i);
729*d57664e9SAndroid Build Coastguard Worker return true;
730*d57664e9SAndroid Build Coastguard Worker }
731*d57664e9SAndroid Build Coastguard Worker }
732*d57664e9SAndroid Build Coastguard Worker return false;
733*d57664e9SAndroid Build Coastguard Worker }
734*d57664e9SAndroid Build Coastguard Worker
editAttribute(const String16 & ns,const String16 & name)735*d57664e9SAndroid Build Coastguard Worker XMLNode::attribute_entry* XMLNode::editAttribute(const String16& ns,
736*d57664e9SAndroid Build Coastguard Worker const String16& name)
737*d57664e9SAndroid Build Coastguard Worker {
738*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<mAttributes.size(); i++) {
739*d57664e9SAndroid Build Coastguard Worker attribute_entry * ae = &mAttributes.editItemAt(i);
740*d57664e9SAndroid Build Coastguard Worker if (ae->ns == ns && ae->name == name) {
741*d57664e9SAndroid Build Coastguard Worker return ae;
742*d57664e9SAndroid Build Coastguard Worker }
743*d57664e9SAndroid Build Coastguard Worker }
744*d57664e9SAndroid Build Coastguard Worker
745*d57664e9SAndroid Build Coastguard Worker return NULL;
746*d57664e9SAndroid Build Coastguard Worker }
747*d57664e9SAndroid Build Coastguard Worker
getCData() const748*d57664e9SAndroid Build Coastguard Worker const String16& XMLNode::getCData() const
749*d57664e9SAndroid Build Coastguard Worker {
750*d57664e9SAndroid Build Coastguard Worker return mChars;
751*d57664e9SAndroid Build Coastguard Worker }
752*d57664e9SAndroid Build Coastguard Worker
getComment() const753*d57664e9SAndroid Build Coastguard Worker const String16& XMLNode::getComment() const
754*d57664e9SAndroid Build Coastguard Worker {
755*d57664e9SAndroid Build Coastguard Worker return mComment;
756*d57664e9SAndroid Build Coastguard Worker }
757*d57664e9SAndroid Build Coastguard Worker
getStartLineNumber() const758*d57664e9SAndroid Build Coastguard Worker int32_t XMLNode::getStartLineNumber() const
759*d57664e9SAndroid Build Coastguard Worker {
760*d57664e9SAndroid Build Coastguard Worker return mStartLineNumber;
761*d57664e9SAndroid Build Coastguard Worker }
762*d57664e9SAndroid Build Coastguard Worker
getEndLineNumber() const763*d57664e9SAndroid Build Coastguard Worker int32_t XMLNode::getEndLineNumber() const
764*d57664e9SAndroid Build Coastguard Worker {
765*d57664e9SAndroid Build Coastguard Worker return mEndLineNumber;
766*d57664e9SAndroid Build Coastguard Worker }
767*d57664e9SAndroid Build Coastguard Worker
searchElement(const String16 & tagNamespace,const String16 & tagName)768*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName)
769*d57664e9SAndroid Build Coastguard Worker {
770*d57664e9SAndroid Build Coastguard Worker if (getType() == XMLNode::TYPE_ELEMENT
771*d57664e9SAndroid Build Coastguard Worker && mNamespaceUri == tagNamespace
772*d57664e9SAndroid Build Coastguard Worker && mElementName == tagName) {
773*d57664e9SAndroid Build Coastguard Worker return this;
774*d57664e9SAndroid Build Coastguard Worker }
775*d57664e9SAndroid Build Coastguard Worker
776*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<mChildren.size(); i++) {
777*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName);
778*d57664e9SAndroid Build Coastguard Worker if (found != NULL) {
779*d57664e9SAndroid Build Coastguard Worker return found;
780*d57664e9SAndroid Build Coastguard Worker }
781*d57664e9SAndroid Build Coastguard Worker }
782*d57664e9SAndroid Build Coastguard Worker
783*d57664e9SAndroid Build Coastguard Worker return NULL;
784*d57664e9SAndroid Build Coastguard Worker }
785*d57664e9SAndroid Build Coastguard Worker
getChildElement(const String16 & tagNamespace,const String16 & tagName)786*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName)
787*d57664e9SAndroid Build Coastguard Worker {
788*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<mChildren.size(); i++) {
789*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> child = mChildren.itemAt(i);
790*d57664e9SAndroid Build Coastguard Worker if (child->getType() == XMLNode::TYPE_ELEMENT
791*d57664e9SAndroid Build Coastguard Worker && child->mNamespaceUri == tagNamespace
792*d57664e9SAndroid Build Coastguard Worker && child->mElementName == tagName) {
793*d57664e9SAndroid Build Coastguard Worker return child;
794*d57664e9SAndroid Build Coastguard Worker }
795*d57664e9SAndroid Build Coastguard Worker }
796*d57664e9SAndroid Build Coastguard Worker
797*d57664e9SAndroid Build Coastguard Worker return NULL;
798*d57664e9SAndroid Build Coastguard Worker }
799*d57664e9SAndroid Build Coastguard Worker
addChild(const sp<XMLNode> & child)800*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::addChild(const sp<XMLNode>& child)
801*d57664e9SAndroid Build Coastguard Worker {
802*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_CDATA) {
803*d57664e9SAndroid Build Coastguard Worker SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node.");
804*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
805*d57664e9SAndroid Build Coastguard Worker }
806*d57664e9SAndroid Build Coastguard Worker //printf("Adding child %p to parent %p\n", child.get(), this);
807*d57664e9SAndroid Build Coastguard Worker mChildren.add(child);
808*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
809*d57664e9SAndroid Build Coastguard Worker }
810*d57664e9SAndroid Build Coastguard Worker
insertChildAt(const sp<XMLNode> & child,size_t index)811*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index)
812*d57664e9SAndroid Build Coastguard Worker {
813*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_CDATA) {
814*d57664e9SAndroid Build Coastguard Worker SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node.");
815*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
816*d57664e9SAndroid Build Coastguard Worker }
817*d57664e9SAndroid Build Coastguard Worker //printf("Adding child %p to parent %p\n", child.get(), this);
818*d57664e9SAndroid Build Coastguard Worker mChildren.insertAt(child, index);
819*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
820*d57664e9SAndroid Build Coastguard Worker }
821*d57664e9SAndroid Build Coastguard Worker
addAttribute(const String16 & ns,const String16 & name,const String16 & value)822*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::addAttribute(const String16& ns, const String16& name,
823*d57664e9SAndroid Build Coastguard Worker const String16& value)
824*d57664e9SAndroid Build Coastguard Worker {
825*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_CDATA) {
826*d57664e9SAndroid Build Coastguard Worker SourcePos(mFilename, getStartLineNumber()).error("Child to CDATA node.");
827*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
828*d57664e9SAndroid Build Coastguard Worker }
829*d57664e9SAndroid Build Coastguard Worker
830*d57664e9SAndroid Build Coastguard Worker if (ns != RESOURCES_TOOLS_NAMESPACE) {
831*d57664e9SAndroid Build Coastguard Worker attribute_entry e;
832*d57664e9SAndroid Build Coastguard Worker e.index = mNextAttributeIndex++;
833*d57664e9SAndroid Build Coastguard Worker e.ns = ns;
834*d57664e9SAndroid Build Coastguard Worker e.name = name;
835*d57664e9SAndroid Build Coastguard Worker e.string = value;
836*d57664e9SAndroid Build Coastguard Worker mAttributes.add(e);
837*d57664e9SAndroid Build Coastguard Worker mAttributeOrder.add(e.index, mAttributes.size()-1);
838*d57664e9SAndroid Build Coastguard Worker }
839*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
840*d57664e9SAndroid Build Coastguard Worker }
841*d57664e9SAndroid Build Coastguard Worker
removeAttribute(size_t index)842*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::removeAttribute(size_t index)
843*d57664e9SAndroid Build Coastguard Worker {
844*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_CDATA) {
845*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
846*d57664e9SAndroid Build Coastguard Worker }
847*d57664e9SAndroid Build Coastguard Worker
848*d57664e9SAndroid Build Coastguard Worker if (index >= mAttributes.size()) {
849*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
850*d57664e9SAndroid Build Coastguard Worker }
851*d57664e9SAndroid Build Coastguard Worker
852*d57664e9SAndroid Build Coastguard Worker const attribute_entry& e = mAttributes[index];
853*d57664e9SAndroid Build Coastguard Worker const uint32_t key = e.nameResId ? e.nameResId : e.index;
854*d57664e9SAndroid Build Coastguard Worker mAttributeOrder.removeItem(key);
855*d57664e9SAndroid Build Coastguard Worker mAttributes.removeAt(index);
856*d57664e9SAndroid Build Coastguard Worker
857*d57664e9SAndroid Build Coastguard Worker // Shift all the indices.
858*d57664e9SAndroid Build Coastguard Worker const size_t attrCount = mAttributeOrder.size();
859*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < attrCount; i++) {
860*d57664e9SAndroid Build Coastguard Worker size_t attrIdx = mAttributeOrder[i];
861*d57664e9SAndroid Build Coastguard Worker if (attrIdx > index) {
862*d57664e9SAndroid Build Coastguard Worker mAttributeOrder.replaceValueAt(i, attrIdx - 1);
863*d57664e9SAndroid Build Coastguard Worker }
864*d57664e9SAndroid Build Coastguard Worker }
865*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
866*d57664e9SAndroid Build Coastguard Worker }
867*d57664e9SAndroid Build Coastguard Worker
setAttributeResID(size_t attrIdx,uint32_t resId)868*d57664e9SAndroid Build Coastguard Worker void XMLNode::setAttributeResID(size_t attrIdx, uint32_t resId)
869*d57664e9SAndroid Build Coastguard Worker {
870*d57664e9SAndroid Build Coastguard Worker attribute_entry& e = mAttributes.editItemAt(attrIdx);
871*d57664e9SAndroid Build Coastguard Worker if (e.nameResId) {
872*d57664e9SAndroid Build Coastguard Worker mAttributeOrder.removeItem(e.nameResId);
873*d57664e9SAndroid Build Coastguard Worker } else {
874*d57664e9SAndroid Build Coastguard Worker mAttributeOrder.removeItem(e.index);
875*d57664e9SAndroid Build Coastguard Worker }
876*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
877*d57664e9SAndroid Build Coastguard Worker printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
878*d57664e9SAndroid Build Coastguard Worker String8(getElementName()).c_str(),
879*d57664e9SAndroid Build Coastguard Worker String8(mAttributes.itemAt(attrIdx).name).c_str(),
880*d57664e9SAndroid Build Coastguard Worker String8(mAttributes.itemAt(attrIdx).string).c_str(),
881*d57664e9SAndroid Build Coastguard Worker resId);
882*d57664e9SAndroid Build Coastguard Worker }
883*d57664e9SAndroid Build Coastguard Worker mAttributes.editItemAt(attrIdx).nameResId = resId;
884*d57664e9SAndroid Build Coastguard Worker mAttributeOrder.add(resId, attrIdx);
885*d57664e9SAndroid Build Coastguard Worker }
886*d57664e9SAndroid Build Coastguard Worker
appendChars(const String16 & chars)887*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::appendChars(const String16& chars)
888*d57664e9SAndroid Build Coastguard Worker {
889*d57664e9SAndroid Build Coastguard Worker if (getType() != TYPE_CDATA) {
890*d57664e9SAndroid Build Coastguard Worker SourcePos(mFilename, getStartLineNumber()).error("Adding characters to element node.");
891*d57664e9SAndroid Build Coastguard Worker return UNKNOWN_ERROR;
892*d57664e9SAndroid Build Coastguard Worker }
893*d57664e9SAndroid Build Coastguard Worker mChars.append(chars);
894*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
895*d57664e9SAndroid Build Coastguard Worker }
896*d57664e9SAndroid Build Coastguard Worker
appendComment(const String16 & comment)897*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::appendComment(const String16& comment)
898*d57664e9SAndroid Build Coastguard Worker {
899*d57664e9SAndroid Build Coastguard Worker if (mComment.size() > 0) {
900*d57664e9SAndroid Build Coastguard Worker mComment.append(String16("\n"));
901*d57664e9SAndroid Build Coastguard Worker }
902*d57664e9SAndroid Build Coastguard Worker mComment.append(comment);
903*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
904*d57664e9SAndroid Build Coastguard Worker }
905*d57664e9SAndroid Build Coastguard Worker
setStartLineNumber(int32_t line)906*d57664e9SAndroid Build Coastguard Worker void XMLNode::setStartLineNumber(int32_t line)
907*d57664e9SAndroid Build Coastguard Worker {
908*d57664e9SAndroid Build Coastguard Worker mStartLineNumber = line;
909*d57664e9SAndroid Build Coastguard Worker }
910*d57664e9SAndroid Build Coastguard Worker
setEndLineNumber(int32_t line)911*d57664e9SAndroid Build Coastguard Worker void XMLNode::setEndLineNumber(int32_t line)
912*d57664e9SAndroid Build Coastguard Worker {
913*d57664e9SAndroid Build Coastguard Worker mEndLineNumber = line;
914*d57664e9SAndroid Build Coastguard Worker }
915*d57664e9SAndroid Build Coastguard Worker
removeWhitespace(bool stripAll,const char ** cDataTags)916*d57664e9SAndroid Build Coastguard Worker void XMLNode::removeWhitespace(bool stripAll, const char** cDataTags)
917*d57664e9SAndroid Build Coastguard Worker {
918*d57664e9SAndroid Build Coastguard Worker //printf("Removing whitespace in %s\n", String8(mElementName).c_str());
919*d57664e9SAndroid Build Coastguard Worker size_t N = mChildren.size();
920*d57664e9SAndroid Build Coastguard Worker if (cDataTags) {
921*d57664e9SAndroid Build Coastguard Worker String8 tag(mElementName);
922*d57664e9SAndroid Build Coastguard Worker const char** p = cDataTags;
923*d57664e9SAndroid Build Coastguard Worker while (*p) {
924*d57664e9SAndroid Build Coastguard Worker if (tag == *p) {
925*d57664e9SAndroid Build Coastguard Worker stripAll = false;
926*d57664e9SAndroid Build Coastguard Worker break;
927*d57664e9SAndroid Build Coastguard Worker }
928*d57664e9SAndroid Build Coastguard Worker }
929*d57664e9SAndroid Build Coastguard Worker }
930*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
931*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = mChildren.itemAt(i);
932*d57664e9SAndroid Build Coastguard Worker if (node->getType() == TYPE_CDATA) {
933*d57664e9SAndroid Build Coastguard Worker // This is a CDATA node...
934*d57664e9SAndroid Build Coastguard Worker const char16_t* p = node->mChars.c_str();
935*d57664e9SAndroid Build Coastguard Worker while (*p != 0 && *p < 128 && isspace(*p)) {
936*d57664e9SAndroid Build Coastguard Worker p++;
937*d57664e9SAndroid Build Coastguard Worker }
938*d57664e9SAndroid Build Coastguard Worker //printf("Space ends at %d in \"%s\"\n",
939*d57664e9SAndroid Build Coastguard Worker // (int)(p-node->mChars.c_str()),
940*d57664e9SAndroid Build Coastguard Worker // String8(node->mChars).c_str());
941*d57664e9SAndroid Build Coastguard Worker if (*p == 0) {
942*d57664e9SAndroid Build Coastguard Worker if (stripAll) {
943*d57664e9SAndroid Build Coastguard Worker // Remove this node!
944*d57664e9SAndroid Build Coastguard Worker mChildren.removeAt(i);
945*d57664e9SAndroid Build Coastguard Worker N--;
946*d57664e9SAndroid Build Coastguard Worker i--;
947*d57664e9SAndroid Build Coastguard Worker } else {
948*d57664e9SAndroid Build Coastguard Worker node->mChars = String16(" ");
949*d57664e9SAndroid Build Coastguard Worker }
950*d57664e9SAndroid Build Coastguard Worker } else {
951*d57664e9SAndroid Build Coastguard Worker // Compact leading/trailing whitespace.
952*d57664e9SAndroid Build Coastguard Worker const char16_t* e = node->mChars.c_str()+node->mChars.size()-1;
953*d57664e9SAndroid Build Coastguard Worker while (e > p && *e < 128 && isspace(*e)) {
954*d57664e9SAndroid Build Coastguard Worker e--;
955*d57664e9SAndroid Build Coastguard Worker }
956*d57664e9SAndroid Build Coastguard Worker if (p > node->mChars.c_str()) {
957*d57664e9SAndroid Build Coastguard Worker p--;
958*d57664e9SAndroid Build Coastguard Worker }
959*d57664e9SAndroid Build Coastguard Worker if (e < (node->mChars.c_str()+node->mChars.size()-1)) {
960*d57664e9SAndroid Build Coastguard Worker e++;
961*d57664e9SAndroid Build Coastguard Worker }
962*d57664e9SAndroid Build Coastguard Worker if (p > node->mChars.c_str() ||
963*d57664e9SAndroid Build Coastguard Worker e < (node->mChars.c_str()+node->mChars.size()-1)) {
964*d57664e9SAndroid Build Coastguard Worker String16 tmp(p, e-p+1);
965*d57664e9SAndroid Build Coastguard Worker node->mChars = tmp;
966*d57664e9SAndroid Build Coastguard Worker }
967*d57664e9SAndroid Build Coastguard Worker }
968*d57664e9SAndroid Build Coastguard Worker } else {
969*d57664e9SAndroid Build Coastguard Worker node->removeWhitespace(stripAll, cDataTags);
970*d57664e9SAndroid Build Coastguard Worker }
971*d57664e9SAndroid Build Coastguard Worker }
972*d57664e9SAndroid Build Coastguard Worker }
973*d57664e9SAndroid Build Coastguard Worker
parseValues(const sp<AaptAssets> & assets,ResourceTable * table)974*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::parseValues(const sp<AaptAssets>& assets,
975*d57664e9SAndroid Build Coastguard Worker ResourceTable* table)
976*d57664e9SAndroid Build Coastguard Worker {
977*d57664e9SAndroid Build Coastguard Worker bool hasErrors = false;
978*d57664e9SAndroid Build Coastguard Worker
979*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_ELEMENT) {
980*d57664e9SAndroid Build Coastguard Worker const size_t N = mAttributes.size();
981*d57664e9SAndroid Build Coastguard Worker String16 defPackage(assets->getPackage());
982*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
983*d57664e9SAndroid Build Coastguard Worker attribute_entry& e = mAttributes.editItemAt(i);
984*d57664e9SAndroid Build Coastguard Worker AccessorCookie ac(SourcePos(mFilename, getStartLineNumber()), String8(e.name),
985*d57664e9SAndroid Build Coastguard Worker String8(e.string));
986*d57664e9SAndroid Build Coastguard Worker table->setCurrentXmlPos(SourcePos(mFilename, getStartLineNumber()));
987*d57664e9SAndroid Build Coastguard Worker if (!assets->getIncludedResources()
988*d57664e9SAndroid Build Coastguard Worker .stringToValue(&e.value, &e.string,
989*d57664e9SAndroid Build Coastguard Worker e.string.c_str(), e.string.size(), true, true,
990*d57664e9SAndroid Build Coastguard Worker e.nameResId, NULL, &defPackage, table, &ac)) {
991*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
992*d57664e9SAndroid Build Coastguard Worker }
993*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
994*d57664e9SAndroid Build Coastguard Worker printf("Attr %s: type=0x%x, str=%s\n",
995*d57664e9SAndroid Build Coastguard Worker String8(e.name).c_str(), e.value.dataType,
996*d57664e9SAndroid Build Coastguard Worker String8(e.string).c_str());
997*d57664e9SAndroid Build Coastguard Worker }
998*d57664e9SAndroid Build Coastguard Worker }
999*d57664e9SAndroid Build Coastguard Worker }
1000*d57664e9SAndroid Build Coastguard Worker const size_t N = mChildren.size();
1001*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
1002*d57664e9SAndroid Build Coastguard Worker status_t err = mChildren.itemAt(i)->parseValues(assets, table);
1003*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1004*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
1005*d57664e9SAndroid Build Coastguard Worker }
1006*d57664e9SAndroid Build Coastguard Worker }
1007*d57664e9SAndroid Build Coastguard Worker return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
1008*d57664e9SAndroid Build Coastguard Worker }
1009*d57664e9SAndroid Build Coastguard Worker
assignResourceIds(const sp<AaptAssets> & assets,const ResourceTable * table)1010*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
1011*d57664e9SAndroid Build Coastguard Worker const ResourceTable* table)
1012*d57664e9SAndroid Build Coastguard Worker {
1013*d57664e9SAndroid Build Coastguard Worker bool hasErrors = false;
1014*d57664e9SAndroid Build Coastguard Worker
1015*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_ELEMENT) {
1016*d57664e9SAndroid Build Coastguard Worker String16 attr("attr");
1017*d57664e9SAndroid Build Coastguard Worker const char* errorMsg;
1018*d57664e9SAndroid Build Coastguard Worker const size_t N = mAttributes.size();
1019*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
1020*d57664e9SAndroid Build Coastguard Worker const attribute_entry& e = mAttributes.itemAt(i);
1021*d57664e9SAndroid Build Coastguard Worker if (e.ns.size() <= 0) continue;
1022*d57664e9SAndroid Build Coastguard Worker bool nsIsPublic = true;
1023*d57664e9SAndroid Build Coastguard Worker String16 pkg(getNamespaceResourcePackage(String16(assets->getPackage()), e.ns, &nsIsPublic));
1024*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1025*d57664e9SAndroid Build Coastguard Worker printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
1026*d57664e9SAndroid Build Coastguard Worker String8(getElementName()).c_str(),
1027*d57664e9SAndroid Build Coastguard Worker String8(e.name).c_str(),
1028*d57664e9SAndroid Build Coastguard Worker String8(e.string).c_str(),
1029*d57664e9SAndroid Build Coastguard Worker String8(e.ns).c_str(),
1030*d57664e9SAndroid Build Coastguard Worker (nsIsPublic) ? "public" : "private",
1031*d57664e9SAndroid Build Coastguard Worker String8(pkg).c_str());
1032*d57664e9SAndroid Build Coastguard Worker }
1033*d57664e9SAndroid Build Coastguard Worker if (pkg.size() <= 0) continue;
1034*d57664e9SAndroid Build Coastguard Worker uint32_t res = table != NULL
1035*d57664e9SAndroid Build Coastguard Worker ? table->getResId(e.name, &attr, &pkg, &errorMsg, nsIsPublic)
1036*d57664e9SAndroid Build Coastguard Worker : assets->getIncludedResources().
1037*d57664e9SAndroid Build Coastguard Worker identifierForName(e.name.c_str(), e.name.size(),
1038*d57664e9SAndroid Build Coastguard Worker attr.c_str(), attr.size(),
1039*d57664e9SAndroid Build Coastguard Worker pkg.c_str(), pkg.size());
1040*d57664e9SAndroid Build Coastguard Worker if (res != 0) {
1041*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1042*d57664e9SAndroid Build Coastguard Worker printf("XML attribute name %s: resid=0x%08x\n",
1043*d57664e9SAndroid Build Coastguard Worker String8(e.name).c_str(), res);
1044*d57664e9SAndroid Build Coastguard Worker }
1045*d57664e9SAndroid Build Coastguard Worker setAttributeResID(i, res);
1046*d57664e9SAndroid Build Coastguard Worker } else {
1047*d57664e9SAndroid Build Coastguard Worker SourcePos(mFilename, getStartLineNumber()).error(
1048*d57664e9SAndroid Build Coastguard Worker "No resource identifier found for attribute '%s' in package '%s'\n",
1049*d57664e9SAndroid Build Coastguard Worker String8(e.name).c_str(), String8(pkg).c_str());
1050*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
1051*d57664e9SAndroid Build Coastguard Worker }
1052*d57664e9SAndroid Build Coastguard Worker }
1053*d57664e9SAndroid Build Coastguard Worker }
1054*d57664e9SAndroid Build Coastguard Worker const size_t N = mChildren.size();
1055*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
1056*d57664e9SAndroid Build Coastguard Worker status_t err = mChildren.itemAt(i)->assignResourceIds(assets, table);
1057*d57664e9SAndroid Build Coastguard Worker if (err < NO_ERROR) {
1058*d57664e9SAndroid Build Coastguard Worker hasErrors = true;
1059*d57664e9SAndroid Build Coastguard Worker }
1060*d57664e9SAndroid Build Coastguard Worker }
1061*d57664e9SAndroid Build Coastguard Worker
1062*d57664e9SAndroid Build Coastguard Worker return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
1063*d57664e9SAndroid Build Coastguard Worker }
1064*d57664e9SAndroid Build Coastguard Worker
clone() const1065*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> XMLNode::clone() const {
1066*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> copy = new XMLNode();
1067*d57664e9SAndroid Build Coastguard Worker copy->mNamespacePrefix = mNamespacePrefix;
1068*d57664e9SAndroid Build Coastguard Worker copy->mNamespaceUri = mNamespaceUri;
1069*d57664e9SAndroid Build Coastguard Worker copy->mElementName = mElementName;
1070*d57664e9SAndroid Build Coastguard Worker
1071*d57664e9SAndroid Build Coastguard Worker const size_t childCount = mChildren.size();
1072*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < childCount; i++) {
1073*d57664e9SAndroid Build Coastguard Worker copy->mChildren.add(mChildren[i]->clone());
1074*d57664e9SAndroid Build Coastguard Worker }
1075*d57664e9SAndroid Build Coastguard Worker
1076*d57664e9SAndroid Build Coastguard Worker copy->mAttributes = mAttributes;
1077*d57664e9SAndroid Build Coastguard Worker copy->mAttributeOrder = mAttributeOrder;
1078*d57664e9SAndroid Build Coastguard Worker copy->mNextAttributeIndex = mNextAttributeIndex;
1079*d57664e9SAndroid Build Coastguard Worker copy->mChars = mChars;
1080*d57664e9SAndroid Build Coastguard Worker memcpy(©->mCharsValue, &mCharsValue, sizeof(mCharsValue));
1081*d57664e9SAndroid Build Coastguard Worker copy->mComment = mComment;
1082*d57664e9SAndroid Build Coastguard Worker copy->mFilename = mFilename;
1083*d57664e9SAndroid Build Coastguard Worker copy->mStartLineNumber = mStartLineNumber;
1084*d57664e9SAndroid Build Coastguard Worker copy->mEndLineNumber = mEndLineNumber;
1085*d57664e9SAndroid Build Coastguard Worker copy->mUTF8 = mUTF8;
1086*d57664e9SAndroid Build Coastguard Worker return copy;
1087*d57664e9SAndroid Build Coastguard Worker }
1088*d57664e9SAndroid Build Coastguard Worker
flatten(const sp<AaptFile> & dest,bool stripComments,bool stripRawValues) const1089*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::flatten(const sp<AaptFile>& dest,
1090*d57664e9SAndroid Build Coastguard Worker bool stripComments, bool stripRawValues) const
1091*d57664e9SAndroid Build Coastguard Worker {
1092*d57664e9SAndroid Build Coastguard Worker StringPool strings(mUTF8);
1093*d57664e9SAndroid Build Coastguard Worker Vector<uint32_t> resids;
1094*d57664e9SAndroid Build Coastguard Worker
1095*d57664e9SAndroid Build Coastguard Worker // First collect just the strings for attribute names that have a
1096*d57664e9SAndroid Build Coastguard Worker // resource ID assigned to them. This ensures that the resource ID
1097*d57664e9SAndroid Build Coastguard Worker // array is compact, and makes it easier to deal with attribute names
1098*d57664e9SAndroid Build Coastguard Worker // in different namespaces (and thus with different resource IDs).
1099*d57664e9SAndroid Build Coastguard Worker collect_resid_strings(&strings, &resids);
1100*d57664e9SAndroid Build Coastguard Worker
1101*d57664e9SAndroid Build Coastguard Worker // Next collect all remainibng strings.
1102*d57664e9SAndroid Build Coastguard Worker collect_strings(&strings, &resids, stripComments, stripRawValues);
1103*d57664e9SAndroid Build Coastguard Worker
1104*d57664e9SAndroid Build Coastguard Worker sp<AaptFile> stringPool = strings.createStringBlock();
1105*d57664e9SAndroid Build Coastguard Worker
1106*d57664e9SAndroid Build Coastguard Worker ResXMLTree_header header;
1107*d57664e9SAndroid Build Coastguard Worker memset(&header, 0, sizeof(header));
1108*d57664e9SAndroid Build Coastguard Worker header.header.type = htods(RES_XML_TYPE);
1109*d57664e9SAndroid Build Coastguard Worker header.header.headerSize = htods(sizeof(header));
1110*d57664e9SAndroid Build Coastguard Worker
1111*d57664e9SAndroid Build Coastguard Worker const size_t basePos = dest->getSize();
1112*d57664e9SAndroid Build Coastguard Worker dest->writeData(&header, sizeof(header));
1113*d57664e9SAndroid Build Coastguard Worker dest->writeData(stringPool->getData(), stringPool->getSize());
1114*d57664e9SAndroid Build Coastguard Worker
1115*d57664e9SAndroid Build Coastguard Worker // If we have resource IDs, write them.
1116*d57664e9SAndroid Build Coastguard Worker if (resids.size() > 0) {
1117*d57664e9SAndroid Build Coastguard Worker const size_t resIdsPos = dest->getSize();
1118*d57664e9SAndroid Build Coastguard Worker const size_t resIdsSize =
1119*d57664e9SAndroid Build Coastguard Worker sizeof(ResChunk_header)+(sizeof(uint32_t)*resids.size());
1120*d57664e9SAndroid Build Coastguard Worker ResChunk_header* idsHeader = (ResChunk_header*)
1121*d57664e9SAndroid Build Coastguard Worker (((const uint8_t*)dest->editData(resIdsPos+resIdsSize))+resIdsPos);
1122*d57664e9SAndroid Build Coastguard Worker idsHeader->type = htods(RES_XML_RESOURCE_MAP_TYPE);
1123*d57664e9SAndroid Build Coastguard Worker idsHeader->headerSize = htods(sizeof(*idsHeader));
1124*d57664e9SAndroid Build Coastguard Worker idsHeader->size = htodl(resIdsSize);
1125*d57664e9SAndroid Build Coastguard Worker uint32_t* ids = (uint32_t*)(idsHeader+1);
1126*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<resids.size(); i++) {
1127*d57664e9SAndroid Build Coastguard Worker *ids++ = htodl(resids[i]);
1128*d57664e9SAndroid Build Coastguard Worker }
1129*d57664e9SAndroid Build Coastguard Worker }
1130*d57664e9SAndroid Build Coastguard Worker
1131*d57664e9SAndroid Build Coastguard Worker flatten_node(strings, dest, stripComments, stripRawValues);
1132*d57664e9SAndroid Build Coastguard Worker
1133*d57664e9SAndroid Build Coastguard Worker void* data = dest->editData();
1134*d57664e9SAndroid Build Coastguard Worker ResXMLTree_header* hd = (ResXMLTree_header*)(((uint8_t*)data)+basePos);
1135*d57664e9SAndroid Build Coastguard Worker hd->header.size = htodl(dest->getSize()-basePos);
1136*d57664e9SAndroid Build Coastguard Worker
1137*d57664e9SAndroid Build Coastguard Worker if (kPrintStringMetrics) {
1138*d57664e9SAndroid Build Coastguard Worker fprintf(stderr, "**** total xml size: %zu / %zu%% strings (in %s)\n",
1139*d57664e9SAndroid Build Coastguard Worker dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
1140*d57664e9SAndroid Build Coastguard Worker dest->getPath().c_str());
1141*d57664e9SAndroid Build Coastguard Worker }
1142*d57664e9SAndroid Build Coastguard Worker
1143*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1144*d57664e9SAndroid Build Coastguard Worker }
1145*d57664e9SAndroid Build Coastguard Worker
print(int indent)1146*d57664e9SAndroid Build Coastguard Worker void XMLNode::print(int indent)
1147*d57664e9SAndroid Build Coastguard Worker {
1148*d57664e9SAndroid Build Coastguard Worker String8 prefix;
1149*d57664e9SAndroid Build Coastguard Worker int i;
1150*d57664e9SAndroid Build Coastguard Worker for (i=0; i<indent; i++) {
1151*d57664e9SAndroid Build Coastguard Worker prefix.append(" ");
1152*d57664e9SAndroid Build Coastguard Worker }
1153*d57664e9SAndroid Build Coastguard Worker if (getType() == TYPE_ELEMENT) {
1154*d57664e9SAndroid Build Coastguard Worker String8 elemNs(getNamespaceUri());
1155*d57664e9SAndroid Build Coastguard Worker if (elemNs.size() > 0) {
1156*d57664e9SAndroid Build Coastguard Worker elemNs.append(":");
1157*d57664e9SAndroid Build Coastguard Worker }
1158*d57664e9SAndroid Build Coastguard Worker printf("%s E: %s%s", prefix.c_str(),
1159*d57664e9SAndroid Build Coastguard Worker elemNs.c_str(), String8(getElementName()).c_str());
1160*d57664e9SAndroid Build Coastguard Worker int N = mAttributes.size();
1161*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
1162*d57664e9SAndroid Build Coastguard Worker ssize_t idx = mAttributeOrder.valueAt(i);
1163*d57664e9SAndroid Build Coastguard Worker if (i == 0) {
1164*d57664e9SAndroid Build Coastguard Worker printf(" / ");
1165*d57664e9SAndroid Build Coastguard Worker } else {
1166*d57664e9SAndroid Build Coastguard Worker printf(", ");
1167*d57664e9SAndroid Build Coastguard Worker }
1168*d57664e9SAndroid Build Coastguard Worker const attribute_entry& attr = mAttributes.itemAt(idx);
1169*d57664e9SAndroid Build Coastguard Worker String8 attrNs(attr.ns);
1170*d57664e9SAndroid Build Coastguard Worker if (attrNs.size() > 0) {
1171*d57664e9SAndroid Build Coastguard Worker attrNs.append(":");
1172*d57664e9SAndroid Build Coastguard Worker }
1173*d57664e9SAndroid Build Coastguard Worker if (attr.nameResId) {
1174*d57664e9SAndroid Build Coastguard Worker printf("%s%s(0x%08x)", attrNs.c_str(),
1175*d57664e9SAndroid Build Coastguard Worker String8(attr.name).c_str(), attr.nameResId);
1176*d57664e9SAndroid Build Coastguard Worker } else {
1177*d57664e9SAndroid Build Coastguard Worker printf("%s%s", attrNs.c_str(), String8(attr.name).c_str());
1178*d57664e9SAndroid Build Coastguard Worker }
1179*d57664e9SAndroid Build Coastguard Worker printf("=%s", String8(attr.string).c_str());
1180*d57664e9SAndroid Build Coastguard Worker }
1181*d57664e9SAndroid Build Coastguard Worker printf("\n");
1182*d57664e9SAndroid Build Coastguard Worker } else if (getType() == TYPE_NAMESPACE) {
1183*d57664e9SAndroid Build Coastguard Worker printf("%s N: %s=%s\n", prefix.c_str(),
1184*d57664e9SAndroid Build Coastguard Worker getNamespacePrefix().size() > 0
1185*d57664e9SAndroid Build Coastguard Worker ? String8(getNamespacePrefix()).c_str() : "<DEF>",
1186*d57664e9SAndroid Build Coastguard Worker String8(getNamespaceUri()).c_str());
1187*d57664e9SAndroid Build Coastguard Worker } else {
1188*d57664e9SAndroid Build Coastguard Worker printf("%s C: \"%s\"\n", prefix.c_str(), String8(getCData()).c_str());
1189*d57664e9SAndroid Build Coastguard Worker }
1190*d57664e9SAndroid Build Coastguard Worker int N = mChildren.size();
1191*d57664e9SAndroid Build Coastguard Worker for (i=0; i<N; i++) {
1192*d57664e9SAndroid Build Coastguard Worker mChildren.itemAt(i)->print(indent+1);
1193*d57664e9SAndroid Build Coastguard Worker }
1194*d57664e9SAndroid Build Coastguard Worker }
1195*d57664e9SAndroid Build Coastguard Worker
splitName(const char * name,String16 * outNs,String16 * outName)1196*d57664e9SAndroid Build Coastguard Worker static void splitName(const char* name, String16* outNs, String16* outName)
1197*d57664e9SAndroid Build Coastguard Worker {
1198*d57664e9SAndroid Build Coastguard Worker const char* p = name;
1199*d57664e9SAndroid Build Coastguard Worker while (*p != 0 && *p != 1) {
1200*d57664e9SAndroid Build Coastguard Worker p++;
1201*d57664e9SAndroid Build Coastguard Worker }
1202*d57664e9SAndroid Build Coastguard Worker if (*p == 0) {
1203*d57664e9SAndroid Build Coastguard Worker *outNs = String16();
1204*d57664e9SAndroid Build Coastguard Worker *outName = String16(name);
1205*d57664e9SAndroid Build Coastguard Worker } else {
1206*d57664e9SAndroid Build Coastguard Worker *outNs = String16(name, (p-name));
1207*d57664e9SAndroid Build Coastguard Worker *outName = String16(p+1);
1208*d57664e9SAndroid Build Coastguard Worker }
1209*d57664e9SAndroid Build Coastguard Worker }
1210*d57664e9SAndroid Build Coastguard Worker
1211*d57664e9SAndroid Build Coastguard Worker void XMLCALL
startNamespace(void * userData,const char * prefix,const char * uri)1212*d57664e9SAndroid Build Coastguard Worker XMLNode::startNamespace(void *userData, const char *prefix, const char *uri)
1213*d57664e9SAndroid Build Coastguard Worker {
1214*d57664e9SAndroid Build Coastguard Worker if (kIsDebugParse) {
1215*d57664e9SAndroid Build Coastguard Worker printf("Start Namespace: %s %s\n", prefix, uri);
1216*d57664e9SAndroid Build Coastguard Worker }
1217*d57664e9SAndroid Build Coastguard Worker ParseState* st = (ParseState*)userData;
1218*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = XMLNode::newNamespace(st->filename,
1219*d57664e9SAndroid Build Coastguard Worker String16(prefix != NULL ? prefix : ""), String16(uri));
1220*d57664e9SAndroid Build Coastguard Worker node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser));
1221*d57664e9SAndroid Build Coastguard Worker if (st->stack.size() > 0) {
1222*d57664e9SAndroid Build Coastguard Worker st->stack.itemAt(st->stack.size()-1)->addChild(node);
1223*d57664e9SAndroid Build Coastguard Worker } else {
1224*d57664e9SAndroid Build Coastguard Worker st->root = node;
1225*d57664e9SAndroid Build Coastguard Worker }
1226*d57664e9SAndroid Build Coastguard Worker st->stack.push(node);
1227*d57664e9SAndroid Build Coastguard Worker }
1228*d57664e9SAndroid Build Coastguard Worker
1229*d57664e9SAndroid Build Coastguard Worker void XMLCALL
startElement(void * userData,const char * name,const char ** atts)1230*d57664e9SAndroid Build Coastguard Worker XMLNode::startElement(void *userData, const char *name, const char **atts)
1231*d57664e9SAndroid Build Coastguard Worker {
1232*d57664e9SAndroid Build Coastguard Worker if (kIsDebugParse) {
1233*d57664e9SAndroid Build Coastguard Worker printf("Start Element: %s\n", name);
1234*d57664e9SAndroid Build Coastguard Worker }
1235*d57664e9SAndroid Build Coastguard Worker ParseState* st = (ParseState*)userData;
1236*d57664e9SAndroid Build Coastguard Worker String16 ns16, name16;
1237*d57664e9SAndroid Build Coastguard Worker splitName(name, &ns16, &name16);
1238*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = XMLNode::newElement(st->filename, ns16, name16);
1239*d57664e9SAndroid Build Coastguard Worker node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser));
1240*d57664e9SAndroid Build Coastguard Worker if (st->pendingComment.size() > 0) {
1241*d57664e9SAndroid Build Coastguard Worker node->appendComment(st->pendingComment);
1242*d57664e9SAndroid Build Coastguard Worker st->pendingComment = String16();
1243*d57664e9SAndroid Build Coastguard Worker }
1244*d57664e9SAndroid Build Coastguard Worker if (st->stack.size() > 0) {
1245*d57664e9SAndroid Build Coastguard Worker st->stack.itemAt(st->stack.size()-1)->addChild(node);
1246*d57664e9SAndroid Build Coastguard Worker } else {
1247*d57664e9SAndroid Build Coastguard Worker st->root = node;
1248*d57664e9SAndroid Build Coastguard Worker }
1249*d57664e9SAndroid Build Coastguard Worker st->stack.push(node);
1250*d57664e9SAndroid Build Coastguard Worker
1251*d57664e9SAndroid Build Coastguard Worker for (int i = 0; atts[i]; i += 2) {
1252*d57664e9SAndroid Build Coastguard Worker splitName(atts[i], &ns16, &name16);
1253*d57664e9SAndroid Build Coastguard Worker node->addAttribute(ns16, name16, String16(atts[i+1]));
1254*d57664e9SAndroid Build Coastguard Worker }
1255*d57664e9SAndroid Build Coastguard Worker }
1256*d57664e9SAndroid Build Coastguard Worker
1257*d57664e9SAndroid Build Coastguard Worker void XMLCALL
characterData(void * userData,const XML_Char * s,int len)1258*d57664e9SAndroid Build Coastguard Worker XMLNode::characterData(void *userData, const XML_Char *s, int len)
1259*d57664e9SAndroid Build Coastguard Worker {
1260*d57664e9SAndroid Build Coastguard Worker if (kIsDebugParse) {
1261*d57664e9SAndroid Build Coastguard Worker printf("CDATA: \"%s\"\n", String8(s, len).c_str());
1262*d57664e9SAndroid Build Coastguard Worker }
1263*d57664e9SAndroid Build Coastguard Worker ParseState* st = (ParseState*)userData;
1264*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = NULL;
1265*d57664e9SAndroid Build Coastguard Worker if (st->stack.size() == 0) {
1266*d57664e9SAndroid Build Coastguard Worker return;
1267*d57664e9SAndroid Build Coastguard Worker }
1268*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> parent = st->stack.itemAt(st->stack.size()-1);
1269*d57664e9SAndroid Build Coastguard Worker if (parent != NULL && parent->getChildren().size() > 0) {
1270*d57664e9SAndroid Build Coastguard Worker node = parent->getChildren()[parent->getChildren().size()-1];
1271*d57664e9SAndroid Build Coastguard Worker if (node->getType() != TYPE_CDATA) {
1272*d57664e9SAndroid Build Coastguard Worker // Last node is not CDATA, need to make a new node.
1273*d57664e9SAndroid Build Coastguard Worker node = NULL;
1274*d57664e9SAndroid Build Coastguard Worker }
1275*d57664e9SAndroid Build Coastguard Worker }
1276*d57664e9SAndroid Build Coastguard Worker
1277*d57664e9SAndroid Build Coastguard Worker if (node == NULL) {
1278*d57664e9SAndroid Build Coastguard Worker node = XMLNode::newCData(st->filename);
1279*d57664e9SAndroid Build Coastguard Worker node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser));
1280*d57664e9SAndroid Build Coastguard Worker parent->addChild(node);
1281*d57664e9SAndroid Build Coastguard Worker }
1282*d57664e9SAndroid Build Coastguard Worker
1283*d57664e9SAndroid Build Coastguard Worker node->appendChars(String16(s, len));
1284*d57664e9SAndroid Build Coastguard Worker }
1285*d57664e9SAndroid Build Coastguard Worker
1286*d57664e9SAndroid Build Coastguard Worker void XMLCALL
endElement(void * userData,const char * name)1287*d57664e9SAndroid Build Coastguard Worker XMLNode::endElement(void *userData, const char *name)
1288*d57664e9SAndroid Build Coastguard Worker {
1289*d57664e9SAndroid Build Coastguard Worker if (kIsDebugParse) {
1290*d57664e9SAndroid Build Coastguard Worker printf("End Element: %s\n", name);
1291*d57664e9SAndroid Build Coastguard Worker }
1292*d57664e9SAndroid Build Coastguard Worker ParseState* st = (ParseState*)userData;
1293*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1);
1294*d57664e9SAndroid Build Coastguard Worker node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser));
1295*d57664e9SAndroid Build Coastguard Worker if (st->pendingComment.size() > 0) {
1296*d57664e9SAndroid Build Coastguard Worker node->appendComment(st->pendingComment);
1297*d57664e9SAndroid Build Coastguard Worker st->pendingComment = String16();
1298*d57664e9SAndroid Build Coastguard Worker }
1299*d57664e9SAndroid Build Coastguard Worker String16 ns16, name16;
1300*d57664e9SAndroid Build Coastguard Worker splitName(name, &ns16, &name16);
1301*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(node->getElementNamespace() != ns16
1302*d57664e9SAndroid Build Coastguard Worker || node->getElementName() != name16,
1303*d57664e9SAndroid Build Coastguard Worker "Bad end element %s", name);
1304*d57664e9SAndroid Build Coastguard Worker st->stack.pop();
1305*d57664e9SAndroid Build Coastguard Worker }
1306*d57664e9SAndroid Build Coastguard Worker
1307*d57664e9SAndroid Build Coastguard Worker void XMLCALL
endNamespace(void * userData,const char * prefix)1308*d57664e9SAndroid Build Coastguard Worker XMLNode::endNamespace(void *userData, const char *prefix)
1309*d57664e9SAndroid Build Coastguard Worker {
1310*d57664e9SAndroid Build Coastguard Worker const char* nonNullPrefix = prefix != NULL ? prefix : "";
1311*d57664e9SAndroid Build Coastguard Worker if (kIsDebugParse) {
1312*d57664e9SAndroid Build Coastguard Worker printf("End Namespace: %s\n", prefix);
1313*d57664e9SAndroid Build Coastguard Worker }
1314*d57664e9SAndroid Build Coastguard Worker ParseState* st = (ParseState*)userData;
1315*d57664e9SAndroid Build Coastguard Worker sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1);
1316*d57664e9SAndroid Build Coastguard Worker node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser));
1317*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(node->getNamespacePrefix() != String16(nonNullPrefix),
1318*d57664e9SAndroid Build Coastguard Worker "Bad end namespace %s", prefix);
1319*d57664e9SAndroid Build Coastguard Worker st->stack.pop();
1320*d57664e9SAndroid Build Coastguard Worker }
1321*d57664e9SAndroid Build Coastguard Worker
1322*d57664e9SAndroid Build Coastguard Worker void XMLCALL
commentData(void * userData,const char * comment)1323*d57664e9SAndroid Build Coastguard Worker XMLNode::commentData(void *userData, const char *comment)
1324*d57664e9SAndroid Build Coastguard Worker {
1325*d57664e9SAndroid Build Coastguard Worker if (kIsDebugParse) {
1326*d57664e9SAndroid Build Coastguard Worker printf("Comment: %s\n", comment);
1327*d57664e9SAndroid Build Coastguard Worker }
1328*d57664e9SAndroid Build Coastguard Worker ParseState* st = (ParseState*)userData;
1329*d57664e9SAndroid Build Coastguard Worker if (st->pendingComment.size() > 0) {
1330*d57664e9SAndroid Build Coastguard Worker st->pendingComment.append(String16("\n"));
1331*d57664e9SAndroid Build Coastguard Worker }
1332*d57664e9SAndroid Build Coastguard Worker st->pendingComment.append(String16(comment));
1333*d57664e9SAndroid Build Coastguard Worker }
1334*d57664e9SAndroid Build Coastguard Worker
collect_strings(StringPool * dest,Vector<uint32_t> * outResIds,bool stripComments,bool stripRawValues) const1335*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::collect_strings(StringPool* dest, Vector<uint32_t>* outResIds,
1336*d57664e9SAndroid Build Coastguard Worker bool stripComments, bool stripRawValues) const
1337*d57664e9SAndroid Build Coastguard Worker {
1338*d57664e9SAndroid Build Coastguard Worker collect_attr_strings(dest, outResIds, true);
1339*d57664e9SAndroid Build Coastguard Worker
1340*d57664e9SAndroid Build Coastguard Worker int i;
1341*d57664e9SAndroid Build Coastguard Worker if (RESOURCES_TOOLS_NAMESPACE != mNamespaceUri) {
1342*d57664e9SAndroid Build Coastguard Worker if (mNamespacePrefix.size() > 0) {
1343*d57664e9SAndroid Build Coastguard Worker dest->add(mNamespacePrefix, true);
1344*d57664e9SAndroid Build Coastguard Worker }
1345*d57664e9SAndroid Build Coastguard Worker if (mNamespaceUri.size() > 0) {
1346*d57664e9SAndroid Build Coastguard Worker dest->add(mNamespaceUri, true);
1347*d57664e9SAndroid Build Coastguard Worker }
1348*d57664e9SAndroid Build Coastguard Worker }
1349*d57664e9SAndroid Build Coastguard Worker if (mElementName.size() > 0) {
1350*d57664e9SAndroid Build Coastguard Worker dest->add(mElementName, true);
1351*d57664e9SAndroid Build Coastguard Worker }
1352*d57664e9SAndroid Build Coastguard Worker
1353*d57664e9SAndroid Build Coastguard Worker if (!stripComments && mComment.size() > 0) {
1354*d57664e9SAndroid Build Coastguard Worker dest->add(mComment, true);
1355*d57664e9SAndroid Build Coastguard Worker }
1356*d57664e9SAndroid Build Coastguard Worker
1357*d57664e9SAndroid Build Coastguard Worker const int NA = mAttributes.size();
1358*d57664e9SAndroid Build Coastguard Worker
1359*d57664e9SAndroid Build Coastguard Worker for (i=0; i<NA; i++) {
1360*d57664e9SAndroid Build Coastguard Worker const attribute_entry& ae = mAttributes.itemAt(i);
1361*d57664e9SAndroid Build Coastguard Worker if (ae.ns.size() > 0) {
1362*d57664e9SAndroid Build Coastguard Worker dest->add(ae.ns, true);
1363*d57664e9SAndroid Build Coastguard Worker }
1364*d57664e9SAndroid Build Coastguard Worker if (!stripRawValues || ae.needStringValue()) {
1365*d57664e9SAndroid Build Coastguard Worker dest->add(ae.string, true);
1366*d57664e9SAndroid Build Coastguard Worker }
1367*d57664e9SAndroid Build Coastguard Worker /*
1368*d57664e9SAndroid Build Coastguard Worker if (ae.value.dataType == Res_value::TYPE_NULL
1369*d57664e9SAndroid Build Coastguard Worker || ae.value.dataType == Res_value::TYPE_STRING) {
1370*d57664e9SAndroid Build Coastguard Worker dest->add(ae.string, true);
1371*d57664e9SAndroid Build Coastguard Worker }
1372*d57664e9SAndroid Build Coastguard Worker */
1373*d57664e9SAndroid Build Coastguard Worker }
1374*d57664e9SAndroid Build Coastguard Worker
1375*d57664e9SAndroid Build Coastguard Worker if (mElementName.size() == 0) {
1376*d57664e9SAndroid Build Coastguard Worker // If not an element, include the CDATA, even if it is empty.
1377*d57664e9SAndroid Build Coastguard Worker dest->add(mChars, true);
1378*d57664e9SAndroid Build Coastguard Worker }
1379*d57664e9SAndroid Build Coastguard Worker
1380*d57664e9SAndroid Build Coastguard Worker const int NC = mChildren.size();
1381*d57664e9SAndroid Build Coastguard Worker
1382*d57664e9SAndroid Build Coastguard Worker for (i=0; i<NC; i++) {
1383*d57664e9SAndroid Build Coastguard Worker mChildren.itemAt(i)->collect_strings(dest, outResIds,
1384*d57664e9SAndroid Build Coastguard Worker stripComments, stripRawValues);
1385*d57664e9SAndroid Build Coastguard Worker }
1386*d57664e9SAndroid Build Coastguard Worker
1387*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1388*d57664e9SAndroid Build Coastguard Worker }
1389*d57664e9SAndroid Build Coastguard Worker
collect_attr_strings(StringPool * outPool,Vector<uint32_t> * outResIds,bool allAttrs) const1390*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::collect_attr_strings(StringPool* outPool,
1391*d57664e9SAndroid Build Coastguard Worker Vector<uint32_t>* outResIds, bool allAttrs) const {
1392*d57664e9SAndroid Build Coastguard Worker const int NA = mAttributes.size();
1393*d57664e9SAndroid Build Coastguard Worker
1394*d57664e9SAndroid Build Coastguard Worker for (int i=0; i<NA; i++) {
1395*d57664e9SAndroid Build Coastguard Worker const attribute_entry& attr = mAttributes.itemAt(i);
1396*d57664e9SAndroid Build Coastguard Worker uint32_t id = attr.nameResId;
1397*d57664e9SAndroid Build Coastguard Worker if (id || allAttrs) {
1398*d57664e9SAndroid Build Coastguard Worker // See if we have already assigned this resource ID to a pooled
1399*d57664e9SAndroid Build Coastguard Worker // string...
1400*d57664e9SAndroid Build Coastguard Worker const Vector<size_t>* indices = outPool->offsetsForString(attr.name);
1401*d57664e9SAndroid Build Coastguard Worker ssize_t idx = -1;
1402*d57664e9SAndroid Build Coastguard Worker if (indices != NULL) {
1403*d57664e9SAndroid Build Coastguard Worker const int NJ = indices->size();
1404*d57664e9SAndroid Build Coastguard Worker const size_t NR = outResIds->size();
1405*d57664e9SAndroid Build Coastguard Worker for (int j=0; j<NJ; j++) {
1406*d57664e9SAndroid Build Coastguard Worker size_t strIdx = indices->itemAt(j);
1407*d57664e9SAndroid Build Coastguard Worker if (strIdx >= NR) {
1408*d57664e9SAndroid Build Coastguard Worker if (id == 0) {
1409*d57664e9SAndroid Build Coastguard Worker // We don't need to assign a resource ID for this one.
1410*d57664e9SAndroid Build Coastguard Worker idx = strIdx;
1411*d57664e9SAndroid Build Coastguard Worker break;
1412*d57664e9SAndroid Build Coastguard Worker }
1413*d57664e9SAndroid Build Coastguard Worker // Just ignore strings that are out of range of
1414*d57664e9SAndroid Build Coastguard Worker // the currently assigned resource IDs... we add
1415*d57664e9SAndroid Build Coastguard Worker // strings as we assign the first ID.
1416*d57664e9SAndroid Build Coastguard Worker } else if (outResIds->itemAt(strIdx) == id) {
1417*d57664e9SAndroid Build Coastguard Worker idx = strIdx;
1418*d57664e9SAndroid Build Coastguard Worker break;
1419*d57664e9SAndroid Build Coastguard Worker }
1420*d57664e9SAndroid Build Coastguard Worker }
1421*d57664e9SAndroid Build Coastguard Worker }
1422*d57664e9SAndroid Build Coastguard Worker if (idx < 0) {
1423*d57664e9SAndroid Build Coastguard Worker idx = outPool->add(attr.name);
1424*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1425*d57664e9SAndroid Build Coastguard Worker printf("Adding attr %s (resid 0x%08x) to pool: idx=%zd\n",
1426*d57664e9SAndroid Build Coastguard Worker String8(attr.name).c_str(), id, idx);
1427*d57664e9SAndroid Build Coastguard Worker }
1428*d57664e9SAndroid Build Coastguard Worker if (id != 0) {
1429*d57664e9SAndroid Build Coastguard Worker while ((ssize_t)outResIds->size() <= idx) {
1430*d57664e9SAndroid Build Coastguard Worker outResIds->add(0);
1431*d57664e9SAndroid Build Coastguard Worker }
1432*d57664e9SAndroid Build Coastguard Worker outResIds->replaceAt(id, idx);
1433*d57664e9SAndroid Build Coastguard Worker }
1434*d57664e9SAndroid Build Coastguard Worker }
1435*d57664e9SAndroid Build Coastguard Worker attr.namePoolIdx = idx;
1436*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1437*d57664e9SAndroid Build Coastguard Worker printf("String %s offset=0x%08zd\n", String8(attr.name).c_str(), idx);
1438*d57664e9SAndroid Build Coastguard Worker }
1439*d57664e9SAndroid Build Coastguard Worker }
1440*d57664e9SAndroid Build Coastguard Worker }
1441*d57664e9SAndroid Build Coastguard Worker
1442*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1443*d57664e9SAndroid Build Coastguard Worker }
1444*d57664e9SAndroid Build Coastguard Worker
collect_resid_strings(StringPool * outPool,Vector<uint32_t> * outResIds) const1445*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::collect_resid_strings(StringPool* outPool,
1446*d57664e9SAndroid Build Coastguard Worker Vector<uint32_t>* outResIds) const
1447*d57664e9SAndroid Build Coastguard Worker {
1448*d57664e9SAndroid Build Coastguard Worker collect_attr_strings(outPool, outResIds, false);
1449*d57664e9SAndroid Build Coastguard Worker
1450*d57664e9SAndroid Build Coastguard Worker const int NC = mChildren.size();
1451*d57664e9SAndroid Build Coastguard Worker
1452*d57664e9SAndroid Build Coastguard Worker for (int i=0; i<NC; i++) {
1453*d57664e9SAndroid Build Coastguard Worker mChildren.itemAt(i)->collect_resid_strings(outPool, outResIds);
1454*d57664e9SAndroid Build Coastguard Worker }
1455*d57664e9SAndroid Build Coastguard Worker
1456*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1457*d57664e9SAndroid Build Coastguard Worker }
1458*d57664e9SAndroid Build Coastguard Worker
flatten_node(const StringPool & strings,const sp<AaptFile> & dest,bool stripComments,bool stripRawValues) const1459*d57664e9SAndroid Build Coastguard Worker status_t XMLNode::flatten_node(const StringPool& strings, const sp<AaptFile>& dest,
1460*d57664e9SAndroid Build Coastguard Worker bool stripComments, bool stripRawValues) const
1461*d57664e9SAndroid Build Coastguard Worker {
1462*d57664e9SAndroid Build Coastguard Worker ResXMLTree_node node;
1463*d57664e9SAndroid Build Coastguard Worker ResXMLTree_cdataExt cdataExt;
1464*d57664e9SAndroid Build Coastguard Worker ResXMLTree_namespaceExt namespaceExt;
1465*d57664e9SAndroid Build Coastguard Worker ResXMLTree_attrExt attrExt;
1466*d57664e9SAndroid Build Coastguard Worker const void* extData = NULL;
1467*d57664e9SAndroid Build Coastguard Worker size_t extSize = 0;
1468*d57664e9SAndroid Build Coastguard Worker ResXMLTree_attribute attr;
1469*d57664e9SAndroid Build Coastguard Worker bool writeCurrentNode = true;
1470*d57664e9SAndroid Build Coastguard Worker
1471*d57664e9SAndroid Build Coastguard Worker const size_t NA = mAttributes.size();
1472*d57664e9SAndroid Build Coastguard Worker const size_t NC = mChildren.size();
1473*d57664e9SAndroid Build Coastguard Worker size_t i;
1474*d57664e9SAndroid Build Coastguard Worker
1475*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(NA != mAttributeOrder.size(), "Attributes messed up!");
1476*d57664e9SAndroid Build Coastguard Worker
1477*d57664e9SAndroid Build Coastguard Worker const String16 id16("id");
1478*d57664e9SAndroid Build Coastguard Worker const String16 class16("class");
1479*d57664e9SAndroid Build Coastguard Worker const String16 style16("style");
1480*d57664e9SAndroid Build Coastguard Worker
1481*d57664e9SAndroid Build Coastguard Worker const type type = getType();
1482*d57664e9SAndroid Build Coastguard Worker
1483*d57664e9SAndroid Build Coastguard Worker memset(&node, 0, sizeof(node));
1484*d57664e9SAndroid Build Coastguard Worker memset(&attr, 0, sizeof(attr));
1485*d57664e9SAndroid Build Coastguard Worker node.header.headerSize = htods(sizeof(node));
1486*d57664e9SAndroid Build Coastguard Worker node.lineNumber = htodl(getStartLineNumber());
1487*d57664e9SAndroid Build Coastguard Worker if (!stripComments) {
1488*d57664e9SAndroid Build Coastguard Worker node.comment.index = htodl(
1489*d57664e9SAndroid Build Coastguard Worker mComment.size() > 0 ? strings.offsetForString(mComment) : -1);
1490*d57664e9SAndroid Build Coastguard Worker //if (mComment.size() > 0) {
1491*d57664e9SAndroid Build Coastguard Worker // printf("Flattening comment: %s\n", String8(mComment).c_str());
1492*d57664e9SAndroid Build Coastguard Worker //}
1493*d57664e9SAndroid Build Coastguard Worker } else {
1494*d57664e9SAndroid Build Coastguard Worker node.comment.index = htodl((uint32_t)-1);
1495*d57664e9SAndroid Build Coastguard Worker }
1496*d57664e9SAndroid Build Coastguard Worker if (type == TYPE_ELEMENT) {
1497*d57664e9SAndroid Build Coastguard Worker node.header.type = htods(RES_XML_START_ELEMENT_TYPE);
1498*d57664e9SAndroid Build Coastguard Worker extData = &attrExt;
1499*d57664e9SAndroid Build Coastguard Worker extSize = sizeof(attrExt);
1500*d57664e9SAndroid Build Coastguard Worker memset(&attrExt, 0, sizeof(attrExt));
1501*d57664e9SAndroid Build Coastguard Worker if (mNamespaceUri.size() > 0) {
1502*d57664e9SAndroid Build Coastguard Worker attrExt.ns.index = htodl(strings.offsetForString(mNamespaceUri));
1503*d57664e9SAndroid Build Coastguard Worker } else {
1504*d57664e9SAndroid Build Coastguard Worker attrExt.ns.index = htodl((uint32_t)-1);
1505*d57664e9SAndroid Build Coastguard Worker }
1506*d57664e9SAndroid Build Coastguard Worker attrExt.name.index = htodl(strings.offsetForString(mElementName));
1507*d57664e9SAndroid Build Coastguard Worker attrExt.attributeStart = htods(sizeof(attrExt));
1508*d57664e9SAndroid Build Coastguard Worker attrExt.attributeSize = htods(sizeof(attr));
1509*d57664e9SAndroid Build Coastguard Worker attrExt.attributeCount = htods(NA);
1510*d57664e9SAndroid Build Coastguard Worker attrExt.idIndex = htods(0);
1511*d57664e9SAndroid Build Coastguard Worker attrExt.classIndex = htods(0);
1512*d57664e9SAndroid Build Coastguard Worker attrExt.styleIndex = htods(0);
1513*d57664e9SAndroid Build Coastguard Worker for (i=0; i<NA; i++) {
1514*d57664e9SAndroid Build Coastguard Worker ssize_t idx = mAttributeOrder.valueAt(i);
1515*d57664e9SAndroid Build Coastguard Worker const attribute_entry& ae = mAttributes.itemAt(idx);
1516*d57664e9SAndroid Build Coastguard Worker if (ae.ns.size() == 0) {
1517*d57664e9SAndroid Build Coastguard Worker if (ae.name == id16) {
1518*d57664e9SAndroid Build Coastguard Worker attrExt.idIndex = htods(i+1);
1519*d57664e9SAndroid Build Coastguard Worker } else if (ae.name == class16) {
1520*d57664e9SAndroid Build Coastguard Worker attrExt.classIndex = htods(i+1);
1521*d57664e9SAndroid Build Coastguard Worker } else if (ae.name == style16) {
1522*d57664e9SAndroid Build Coastguard Worker attrExt.styleIndex = htods(i+1);
1523*d57664e9SAndroid Build Coastguard Worker }
1524*d57664e9SAndroid Build Coastguard Worker }
1525*d57664e9SAndroid Build Coastguard Worker }
1526*d57664e9SAndroid Build Coastguard Worker } else if (type == TYPE_NAMESPACE) {
1527*d57664e9SAndroid Build Coastguard Worker if (mNamespaceUri == RESOURCES_TOOLS_NAMESPACE) {
1528*d57664e9SAndroid Build Coastguard Worker writeCurrentNode = false;
1529*d57664e9SAndroid Build Coastguard Worker } else {
1530*d57664e9SAndroid Build Coastguard Worker node.header.type = htods(RES_XML_START_NAMESPACE_TYPE);
1531*d57664e9SAndroid Build Coastguard Worker extData = &namespaceExt;
1532*d57664e9SAndroid Build Coastguard Worker extSize = sizeof(namespaceExt);
1533*d57664e9SAndroid Build Coastguard Worker memset(&namespaceExt, 0, sizeof(namespaceExt));
1534*d57664e9SAndroid Build Coastguard Worker if (mNamespacePrefix.size() > 0) {
1535*d57664e9SAndroid Build Coastguard Worker namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix));
1536*d57664e9SAndroid Build Coastguard Worker } else {
1537*d57664e9SAndroid Build Coastguard Worker namespaceExt.prefix.index = htodl((uint32_t)-1);
1538*d57664e9SAndroid Build Coastguard Worker }
1539*d57664e9SAndroid Build Coastguard Worker namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix));
1540*d57664e9SAndroid Build Coastguard Worker namespaceExt.uri.index = htodl(strings.offsetForString(mNamespaceUri));
1541*d57664e9SAndroid Build Coastguard Worker }
1542*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(NA != 0, "Namespace nodes can't have attributes!");
1543*d57664e9SAndroid Build Coastguard Worker } else if (type == TYPE_CDATA) {
1544*d57664e9SAndroid Build Coastguard Worker node.header.type = htods(RES_XML_CDATA_TYPE);
1545*d57664e9SAndroid Build Coastguard Worker extData = &cdataExt;
1546*d57664e9SAndroid Build Coastguard Worker extSize = sizeof(cdataExt);
1547*d57664e9SAndroid Build Coastguard Worker memset(&cdataExt, 0, sizeof(cdataExt));
1548*d57664e9SAndroid Build Coastguard Worker cdataExt.data.index = htodl(strings.offsetForString(mChars));
1549*d57664e9SAndroid Build Coastguard Worker cdataExt.typedData.size = htods(sizeof(cdataExt.typedData));
1550*d57664e9SAndroid Build Coastguard Worker cdataExt.typedData.res0 = 0;
1551*d57664e9SAndroid Build Coastguard Worker cdataExt.typedData.dataType = mCharsValue.dataType;
1552*d57664e9SAndroid Build Coastguard Worker cdataExt.typedData.data = htodl(mCharsValue.data);
1553*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(NA != 0, "CDATA nodes can't have attributes!");
1554*d57664e9SAndroid Build Coastguard Worker }
1555*d57664e9SAndroid Build Coastguard Worker
1556*d57664e9SAndroid Build Coastguard Worker node.header.size = htodl(sizeof(node) + extSize + (sizeof(attr)*NA));
1557*d57664e9SAndroid Build Coastguard Worker
1558*d57664e9SAndroid Build Coastguard Worker if (writeCurrentNode) {
1559*d57664e9SAndroid Build Coastguard Worker dest->writeData(&node, sizeof(node));
1560*d57664e9SAndroid Build Coastguard Worker if (extSize > 0) {
1561*d57664e9SAndroid Build Coastguard Worker dest->writeData(extData, extSize);
1562*d57664e9SAndroid Build Coastguard Worker }
1563*d57664e9SAndroid Build Coastguard Worker }
1564*d57664e9SAndroid Build Coastguard Worker
1565*d57664e9SAndroid Build Coastguard Worker for (i=0; i<NA; i++) {
1566*d57664e9SAndroid Build Coastguard Worker ssize_t idx = mAttributeOrder.valueAt(i);
1567*d57664e9SAndroid Build Coastguard Worker const attribute_entry& ae = mAttributes.itemAt(idx);
1568*d57664e9SAndroid Build Coastguard Worker if (ae.ns.size() > 0) {
1569*d57664e9SAndroid Build Coastguard Worker attr.ns.index = htodl(strings.offsetForString(ae.ns));
1570*d57664e9SAndroid Build Coastguard Worker } else {
1571*d57664e9SAndroid Build Coastguard Worker attr.ns.index = htodl((uint32_t)-1);
1572*d57664e9SAndroid Build Coastguard Worker }
1573*d57664e9SAndroid Build Coastguard Worker attr.name.index = htodl(ae.namePoolIdx);
1574*d57664e9SAndroid Build Coastguard Worker
1575*d57664e9SAndroid Build Coastguard Worker if (!stripRawValues || ae.needStringValue()) {
1576*d57664e9SAndroid Build Coastguard Worker attr.rawValue.index = htodl(strings.offsetForString(ae.string));
1577*d57664e9SAndroid Build Coastguard Worker } else {
1578*d57664e9SAndroid Build Coastguard Worker attr.rawValue.index = htodl((uint32_t)-1);
1579*d57664e9SAndroid Build Coastguard Worker }
1580*d57664e9SAndroid Build Coastguard Worker attr.typedValue.size = htods(sizeof(attr.typedValue));
1581*d57664e9SAndroid Build Coastguard Worker if (ae.value.dataType == Res_value::TYPE_NULL
1582*d57664e9SAndroid Build Coastguard Worker || ae.value.dataType == Res_value::TYPE_STRING) {
1583*d57664e9SAndroid Build Coastguard Worker attr.typedValue.res0 = 0;
1584*d57664e9SAndroid Build Coastguard Worker attr.typedValue.dataType = Res_value::TYPE_STRING;
1585*d57664e9SAndroid Build Coastguard Worker attr.typedValue.data = htodl(strings.offsetForString(ae.string));
1586*d57664e9SAndroid Build Coastguard Worker } else {
1587*d57664e9SAndroid Build Coastguard Worker attr.typedValue.res0 = 0;
1588*d57664e9SAndroid Build Coastguard Worker attr.typedValue.dataType = ae.value.dataType;
1589*d57664e9SAndroid Build Coastguard Worker attr.typedValue.data = htodl(ae.value.data);
1590*d57664e9SAndroid Build Coastguard Worker }
1591*d57664e9SAndroid Build Coastguard Worker dest->writeData(&attr, sizeof(attr));
1592*d57664e9SAndroid Build Coastguard Worker }
1593*d57664e9SAndroid Build Coastguard Worker
1594*d57664e9SAndroid Build Coastguard Worker for (i=0; i<NC; i++) {
1595*d57664e9SAndroid Build Coastguard Worker status_t err = mChildren.itemAt(i)->flatten_node(strings, dest,
1596*d57664e9SAndroid Build Coastguard Worker stripComments, stripRawValues);
1597*d57664e9SAndroid Build Coastguard Worker if (err != NO_ERROR) {
1598*d57664e9SAndroid Build Coastguard Worker return err;
1599*d57664e9SAndroid Build Coastguard Worker }
1600*d57664e9SAndroid Build Coastguard Worker }
1601*d57664e9SAndroid Build Coastguard Worker
1602*d57664e9SAndroid Build Coastguard Worker if (type == TYPE_ELEMENT) {
1603*d57664e9SAndroid Build Coastguard Worker ResXMLTree_endElementExt endElementExt;
1604*d57664e9SAndroid Build Coastguard Worker memset(&endElementExt, 0, sizeof(endElementExt));
1605*d57664e9SAndroid Build Coastguard Worker node.header.type = htods(RES_XML_END_ELEMENT_TYPE);
1606*d57664e9SAndroid Build Coastguard Worker node.header.size = htodl(sizeof(node)+sizeof(endElementExt));
1607*d57664e9SAndroid Build Coastguard Worker node.lineNumber = htodl(getEndLineNumber());
1608*d57664e9SAndroid Build Coastguard Worker node.comment.index = htodl((uint32_t)-1);
1609*d57664e9SAndroid Build Coastguard Worker endElementExt.ns.index = attrExt.ns.index;
1610*d57664e9SAndroid Build Coastguard Worker endElementExt.name.index = attrExt.name.index;
1611*d57664e9SAndroid Build Coastguard Worker dest->writeData(&node, sizeof(node));
1612*d57664e9SAndroid Build Coastguard Worker dest->writeData(&endElementExt, sizeof(endElementExt));
1613*d57664e9SAndroid Build Coastguard Worker } else if (type == TYPE_NAMESPACE) {
1614*d57664e9SAndroid Build Coastguard Worker if (writeCurrentNode) {
1615*d57664e9SAndroid Build Coastguard Worker node.header.type = htods(RES_XML_END_NAMESPACE_TYPE);
1616*d57664e9SAndroid Build Coastguard Worker node.lineNumber = htodl(getEndLineNumber());
1617*d57664e9SAndroid Build Coastguard Worker node.comment.index = htodl((uint32_t)-1);
1618*d57664e9SAndroid Build Coastguard Worker node.header.size = htodl(sizeof(node)+extSize);
1619*d57664e9SAndroid Build Coastguard Worker dest->writeData(&node, sizeof(node));
1620*d57664e9SAndroid Build Coastguard Worker dest->writeData(extData, extSize);
1621*d57664e9SAndroid Build Coastguard Worker }
1622*d57664e9SAndroid Build Coastguard Worker }
1623*d57664e9SAndroid Build Coastguard Worker
1624*d57664e9SAndroid Build Coastguard Worker return NO_ERROR;
1625*d57664e9SAndroid Build Coastguard Worker }
1626