1 package org.robolectric.res.android;
2
3 import static org.robolectric.res.android.Errors.BAD_TYPE;
4 import static org.robolectric.res.android.Errors.NAME_NOT_FOUND;
5 import static org.robolectric.res.android.Errors.NO_ERROR;
6 import static org.robolectric.res.android.ResTable.kDebugStringPoolNoisy;
7 import static org.robolectric.res.android.ResTable.kDebugXMLNoisy;
8 import static org.robolectric.res.android.ResXMLParser.event_code_t.BAD_DOCUMENT;
9 import static org.robolectric.res.android.ResXMLParser.event_code_t.END_DOCUMENT;
10 import static org.robolectric.res.android.ResXMLParser.event_code_t.END_NAMESPACE;
11 import static org.robolectric.res.android.ResXMLParser.event_code_t.END_TAG;
12 import static org.robolectric.res.android.ResXMLParser.event_code_t.FIRST_CHUNK_CODE;
13 import static org.robolectric.res.android.ResXMLParser.event_code_t.START_DOCUMENT;
14 import static org.robolectric.res.android.ResXMLParser.event_code_t.START_NAMESPACE;
15 import static org.robolectric.res.android.ResXMLParser.event_code_t.START_TAG;
16 import static org.robolectric.res.android.ResXMLParser.event_code_t.TEXT;
17 import static org.robolectric.res.android.ResourceTypes.RES_XML_CDATA_TYPE;
18 import static org.robolectric.res.android.ResourceTypes.RES_XML_END_ELEMENT_TYPE;
19 import static org.robolectric.res.android.ResourceTypes.RES_XML_END_NAMESPACE_TYPE;
20 import static org.robolectric.res.android.ResourceTypes.RES_XML_FIRST_CHUNK_TYPE;
21 import static org.robolectric.res.android.ResourceTypes.RES_XML_START_ELEMENT_TYPE;
22 import static org.robolectric.res.android.ResourceTypes.RES_XML_START_NAMESPACE_TYPE;
23 import static org.robolectric.res.android.Util.ALOGI;
24 import static org.robolectric.res.android.Util.ALOGW;
25 import static org.robolectric.res.android.Util.dtohl;
26 import static org.robolectric.res.android.Util.dtohs;
27 import static org.robolectric.res.android.Util.isTruthy;
28
29 import org.robolectric.res.android.ResourceTypes.ResChunk_header;
30 import org.robolectric.res.android.ResourceTypes.ResXMLTree_attrExt;
31 import org.robolectric.res.android.ResourceTypes.ResXMLTree_attribute;
32 import org.robolectric.res.android.ResourceTypes.ResXMLTree_endElementExt;
33 import org.robolectric.res.android.ResourceTypes.ResXMLTree_node;
34 import org.robolectric.res.android.ResourceTypes.Res_value;
35
36 public class ResXMLParser {
37
38 static final int SIZEOF_RESXMLTREE_NAMESPACE_EXT = 4;
39 static final int SIZEOF_RESXMLTREE_NODE = ResChunk_header.SIZEOF + 8;
40 static final int SIZEOF_RESXMLTREE_ATTR_EXT = 20;
41 static final int SIZEOF_RESXMLTREE_CDATA_EXT = 4 + ResourceTypes.Res_value.SIZEOF;
42 static final int SIZEOF_CHAR = 2;
43
44 public static class event_code_t {
45 public static final int BAD_DOCUMENT = -1;
46 public static final int START_DOCUMENT = 0;
47 public static final int END_DOCUMENT = 1;
48
49 public static final int FIRST_CHUNK_CODE = RES_XML_FIRST_CHUNK_TYPE;
50
51 public static final int START_NAMESPACE = RES_XML_START_NAMESPACE_TYPE;
52 public static final int END_NAMESPACE = RES_XML_END_NAMESPACE_TYPE;
53 public static final int START_TAG = RES_XML_START_ELEMENT_TYPE;
54 public static final int END_TAG = RES_XML_END_ELEMENT_TYPE;
55 public static final int TEXT = RES_XML_CDATA_TYPE;
56 }
57
58 ResXMLTree mTree;
59 int mEventCode;
60 ResXMLTree_node mCurNode;
61 int mCurExt;
62 int mSourceResourceId;
63
ResXMLParser(ResXMLTree tree)64 public ResXMLParser(ResXMLTree tree) {
65 this.mTree = tree;
66 this.mEventCode = BAD_DOCUMENT;
67 }
68
restart()69 public void restart() {
70 mCurNode = null;
71 mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
72 }
73
getStrings()74 public ResStringPool getStrings() {
75 return mTree.mStrings;
76 }
77
getEventType()78 int getEventType()
79 {
80 return mEventCode;
81 }
82
next()83 public int next()
84 {
85 if (mEventCode == START_DOCUMENT) {
86 mCurNode = mTree.mRootNode;
87 mCurExt = mTree.mRootExt;
88 return (mEventCode=mTree.mRootCode);
89 } else if (mEventCode >= FIRST_CHUNK_CODE) {
90 return nextNode();
91 }
92 return mEventCode;
93 }
94
getCommentID()95 int getCommentID()
96 {
97 return mCurNode != null ? dtohl(mCurNode.comment.index) : -1;
98 }
99
getComment(Ref<Integer> outLen)100 final String getComment(Ref<Integer> outLen)
101 {
102 int id = getCommentID();
103 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
104 }
105
getLineNumber()106 public int getLineNumber()
107 {
108 return mCurNode != null ? dtohl(mCurNode.lineNumber) : -1;
109 }
110
getTextID()111 public int getTextID()
112 {
113 if (mEventCode == TEXT) {
114 return dtohl(new ResourceTypes.ResXMLTree_cdataExt(mTree.mBuffer.buf, mCurExt).data.index);
115 }
116 return -1;
117 }
118
getText(Ref<Integer> outLen)119 final String getText(Ref<Integer> outLen)
120 {
121 int id = getTextID();
122 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
123 }
124
getTextValue(Res_value outValue)125 int getTextValue(Res_value outValue)
126 {
127 if (mEventCode == TEXT) {
128 //outValue.copyFrom_dtoh(new ResourceTypes.ResXMLTree_cdataExt(mTree.mBuffer.buf, mCurExt).typedData);
129 return ResourceTypes.Res_value.SIZEOF /* sizeof(Res_value) */;
130 }
131 return BAD_TYPE;
132 }
133
getNamespacePrefixID()134 int getNamespacePrefixID()
135 {
136 if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
137 return dtohl(new ResourceTypes.ResXMLTree_namespaceExt(mTree.mBuffer.buf, mCurExt).prefix.index);
138 }
139 return -1;
140 }
141
getNamespacePrefix(Ref<Integer> outLen)142 final String getNamespacePrefix(Ref<Integer> outLen)
143 {
144 int id = getNamespacePrefixID();
145 //printf("prefix=%d event=%s\n", id, mEventCode);
146 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
147 }
148
getNamespaceUriID()149 int getNamespaceUriID()
150 {
151 if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
152 return dtohl(new ResourceTypes.ResXMLTree_namespaceExt(mTree.mBuffer.buf, mCurExt).uri.index);
153 }
154 return -1;
155 }
156
getNamespaceUri(Ref<Integer> outLen)157 final String getNamespaceUri(Ref<Integer> outLen)
158 {
159 int id = getNamespaceUriID();
160 //printf("uri=%d event=%s\n", id, mEventCode);
161 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
162 }
163
getElementNamespaceID()164 public int getElementNamespaceID()
165 {
166 if (mEventCode == START_TAG) {
167 return dtohl(new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt).ns.index);
168 }
169 if (mEventCode == END_TAG) {
170 return dtohl(new ResXMLTree_endElementExt(mTree.mBuffer.buf, mCurExt).ns.index);
171 }
172 return -1;
173 }
174
getElementNamespace(Ref<Integer> outLen)175 final String getElementNamespace(Ref<Integer> outLen)
176 {
177 int id = getElementNamespaceID();
178 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
179 }
180
getElementNameID()181 public int getElementNameID()
182 {
183 if (mEventCode == START_TAG) {
184 return dtohl(new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt).name.index);
185 }
186 if (mEventCode == END_TAG) {
187 return dtohl(new ResXMLTree_endElementExt(mTree.mBuffer.buf, mCurExt).name.index);
188 }
189 return -1;
190 }
191
getElementName(Ref<Integer> outLen)192 final String getElementName(Ref<Integer> outLen)
193 {
194 int id = getElementNameID();
195 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
196 }
197
getAttributeCount()198 public int getAttributeCount()
199 {
200 if (mEventCode == START_TAG) {
201 return dtohs(new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt).attributeCount);
202 }
203 return 0;
204 }
205
getAttributeNamespaceID(int idx)206 public int getAttributeNamespaceID(int idx)
207 {
208 if (mEventCode == START_TAG) {
209 ResXMLTree_attrExt tag = new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt);
210 if (idx < dtohs(tag.attributeCount)) {
211 // final ResXMLTree_attribute attr = (ResXMLTree_attribute)
212 // (((final int8_t*)tag)
213 // + dtohs(tag.attributeStart())
214 // + (dtohs(tag.attributeSize())*idx));
215 ResXMLTree_attribute attr = tag.attributeAt(idx);
216 return dtohl(attr.ns.index);
217 }
218 }
219 return -2;
220 }
221
getAttributeNamespace(int idx, Ref<Integer> outLen)222 final String getAttributeNamespace(int idx, Ref<Integer> outLen)
223 {
224 int id = getAttributeNamespaceID(idx);
225 //printf("attribute namespace=%d idx=%d event=%s\n", id, idx, mEventCode);
226 if (kDebugXMLNoisy) {
227 System.out.println(String.format("getAttributeNamespace 0x%x=0x%x\n", idx, id));
228 }
229 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
230 }
231
getAttributeNamespace8(int idx, Ref<Integer> outLen)232 final String getAttributeNamespace8(int idx, Ref<Integer> outLen)
233 {
234 int id = getAttributeNamespaceID(idx);
235 //printf("attribute namespace=%d idx=%d event=%s\n", id, idx, mEventCode);
236 if (kDebugXMLNoisy) {
237 System.out.println(String.format("getAttributeNamespace 0x%x=0x%x\n", idx, id));
238 }
239 return id >= 0 ? mTree.mStrings.string8At(id, outLen) : null;
240 }
241
getAttributeNameID(int idx)242 public int getAttributeNameID(int idx)
243 {
244 if (mEventCode == START_TAG) {
245 ResXMLTree_attrExt tag = new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt);
246 if (idx < dtohs(tag.attributeCount)) {
247 // final ResXMLTree_attribute attr = (ResXMLTree_attribute)
248 // (((final int8_t*)tag)
249 // + dtohs(tag.attributeStart())
250 // + (dtohs(tag.attributeSize())*idx));
251 ResXMLTree_attribute attr = tag.attributeAt(idx);
252 return dtohl(attr.name.index);
253 }
254 }
255 return -1;
256 }
257
getAttributeName(int idx, Ref<Integer> outLen)258 final String getAttributeName(int idx, Ref<Integer> outLen)
259 {
260 int id = getAttributeNameID(idx);
261 //printf("attribute name=%d idx=%d event=%s\n", id, idx, mEventCode);
262 if (kDebugXMLNoisy) {
263 System.out.println(String.format("getAttributeName 0x%x=0x%x\n", idx, id));
264 }
265 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
266 }
267
getAttributeName8(int idx, Ref<Integer> outLen)268 final String getAttributeName8(int idx, Ref<Integer> outLen)
269 {
270 int id = getAttributeNameID(idx);
271 //printf("attribute name=%d idx=%d event=%s\n", id, idx, mEventCode);
272 if (kDebugXMLNoisy) {
273 System.out.println(String.format("getAttributeName 0x%x=0x%x\n", idx, id));
274 }
275 return id >= 0 ? mTree.mStrings.string8At(id, outLen) : null;
276 }
277
getAttributeNameResID(int idx)278 public int getAttributeNameResID(int idx)
279 {
280 int id = getAttributeNameID(idx);
281 if (id >= 0 && (int)id < mTree.mNumResIds) {
282 int resId = dtohl(mTree.mResIds[id]);
283 if (mTree.mDynamicRefTable != null) {
284 final Ref<Integer> resIdRef = new Ref<>(resId);
285 mTree.mDynamicRefTable.lookupResourceId(resIdRef);
286 resId = resIdRef.get();
287 }
288 return resId;
289 }
290 return 0;
291 }
292
getAttributeValueStringID(int idx)293 public int getAttributeValueStringID(int idx)
294 {
295 if (mEventCode == START_TAG) {
296 ResXMLTree_attrExt tag = new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt);
297 if (idx < dtohs(tag.attributeCount)) {
298 // final ResXMLTree_attribute attr = (ResXMLTree_attribute)
299 // (((final int8_t*)tag)
300 // + dtohs(tag.attributeStart())
301 // + (dtohs(tag.attributeSize())*idx));
302 ResXMLTree_attribute attr = tag.attributeAt(idx);
303 return dtohl(attr.rawValue.index);
304 }
305 }
306 return -1;
307 }
308
getAttributeStringValue(int idx, Ref<Integer> outLen)309 final String getAttributeStringValue(int idx, Ref<Integer> outLen)
310 {
311 int id = getAttributeValueStringID(idx);
312 if (kDebugXMLNoisy) {
313 System.out.println(String.format("getAttributeValue 0x%x=0x%x\n", idx, id));
314 }
315 return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
316 }
317
getAttributeDataType(int idx)318 public int getAttributeDataType(int idx)
319 {
320 if (mEventCode == START_TAG) {
321 final ResXMLTree_attrExt tag = new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt);
322 if (idx < dtohs(tag.attributeCount)) {
323 // final ResXMLTree_attribute attr = (ResXMLTree_attribute)
324 // (((final int8_t*)tag)
325 // + dtohs(tag.attributeStart())
326 // + (dtohs(tag.attributeSize())*idx));
327 ResXMLTree_attribute attr = tag.attributeAt(idx);
328 int type = attr.typedValue.dataType;
329 if (type != DataType.DYNAMIC_REFERENCE.code()) {
330 return type;
331 }
332
333 // This is a dynamic reference. We adjust those references
334 // to regular references at this level, so lie to the caller.
335 return DataType.REFERENCE.code();
336 }
337 }
338 return DataType.NULL.code();
339 }
340
getAttributeData(int idx)341 public int getAttributeData(int idx)
342 {
343 if (mEventCode == START_TAG) {
344 ResXMLTree_attrExt tag = new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt);
345 if (idx < dtohs(tag.attributeCount)) {
346 // final ResXMLTree_attribute attr = (ResXMLTree_attribute)
347 // (((final int8_t*)tag)
348 // + dtohs(tag.attributeStart)
349 // + (dtohs(tag.attributeSize)*idx));
350 ResXMLTree_attribute attr = tag.attributeAt(idx);
351 if (attr.typedValue.dataType != DataType.DYNAMIC_REFERENCE.code() ||
352 mTree.mDynamicRefTable == null) {
353 return dtohl(attr.typedValue.data);
354 }
355
356 final Ref<Integer> data = new Ref<>(dtohl(attr.typedValue.data));
357 if (mTree.mDynamicRefTable.lookupResourceId(data) == NO_ERROR) {
358 return data.get();
359 }
360 }
361 }
362 return 0;
363 }
364
getAttributeValue(int idx, Ref<Res_value> outValue)365 public int getAttributeValue(int idx, Ref<Res_value> outValue)
366 {
367 if (mEventCode == START_TAG) {
368 ResXMLTree_attrExt tag = new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt);
369 if (idx < dtohs(tag.attributeCount)) {
370 // final ResXMLTree_attribute attr = (ResXMLTree_attribute)
371 // (((final int8_t*)tag)
372 // + dtohs(tag.attributeStart())
373 // + (dtohs(tag.attributeSize())*idx));
374 ResXMLTree_attribute attr = tag.attributeAt(idx);
375 outValue.set(attr.typedValue);
376 if (mTree.mDynamicRefTable != null &&
377 mTree.mDynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
378 return BAD_TYPE;
379 }
380 return ResourceTypes.Res_value.SIZEOF /* sizeof(Res_value) */;
381 }
382 }
383 return BAD_TYPE;
384 }
385
indexOfAttribute(final String ns, final String attr)386 int indexOfAttribute(final String ns, final String attr)
387 {
388 String nsStr = ns != null ? ns : "";
389 String attrStr = attr;
390 return indexOfAttribute(isTruthy(ns) ? nsStr : null, isTruthy(ns) ? nsStr.length() : 0,
391 attrStr, attrStr.length());
392 }
393
indexOfAttribute(final String ns, int nsLen, final String attr, int attrLen)394 public int indexOfAttribute(final String ns, int nsLen,
395 final String attr, int attrLen)
396 {
397 if (mEventCode == START_TAG) {
398 if (attr == null) {
399 return NAME_NOT_FOUND;
400 }
401 final int N = getAttributeCount();
402 if (mTree.mStrings.isUTF8()) {
403 String8 ns8 = null, attr8;
404 if (ns != null) {
405 ns8 = new String8(ns, nsLen);
406 }
407 attr8 = new String8(attr, attrLen);
408 if (kDebugStringPoolNoisy) {
409 ALOGI("indexOfAttribute UTF8 %s (0x%x) / %s (0x%x)", ns8.string(), nsLen,
410 attr8.string(), attrLen);
411 }
412 for (int i=0; i<N; i++) {
413 final Ref<Integer> curNsLen = new Ref<>(0), curAttrLen = new Ref<>(0);
414 final String curNs = getAttributeNamespace8(i, curNsLen);
415 final String curAttr = getAttributeName8(i, curAttrLen);
416 if (kDebugStringPoolNoisy) {
417 ALOGI(" curNs=%s (0x%x), curAttr=%s (0x%x)", curNs, curNsLen.get(), curAttr, curAttrLen.get());
418 }
419 if (curAttr != null && curNsLen.get() == nsLen && curAttrLen.get() == attrLen
420 && memcmp(attr8.string(), curAttr, attrLen) == 0) {
421 if (ns == null) {
422 if (curNs == null) {
423 if (kDebugStringPoolNoisy) {
424 ALOGI(" FOUND!");
425 }
426 return i;
427 }
428 } else if (curNs != null) {
429 //printf(" -. ns=%s, curNs=%s\n",
430 // String8(ns).string(), String8(curNs).string());
431 if (memcmp(ns8.string(), curNs, nsLen) == 0) {
432 if (kDebugStringPoolNoisy) {
433 ALOGI(" FOUND!");
434 }
435 return i;
436 }
437 }
438 }
439 }
440 } else {
441 if (kDebugStringPoolNoisy) {
442 ALOGI("indexOfAttribute UTF16 %s (0x%x) / %s (0x%x)",
443 ns /*String8(ns, nsLen).string()*/, nsLen,
444 attr /*String8(attr, attrLen).string()*/, attrLen);
445 }
446 for (int i=0; i<N; i++) {
447 final Ref<Integer> curNsLen = new Ref<>(0), curAttrLen = new Ref<>(0);
448 final String curNs = getAttributeNamespace(i, curNsLen);
449 final String curAttr = getAttributeName(i, curAttrLen);
450 if (kDebugStringPoolNoisy) {
451 ALOGI(" curNs=%s (0x%x), curAttr=%s (0x%x)",
452 curNs /*String8(curNs, curNsLen).string()*/, curNsLen.get(),
453 curAttr /*String8(curAttr, curAttrLen).string()*/, curAttrLen.get());
454 }
455 if (curAttr != null && curNsLen.get() == nsLen && curAttrLen.get() == attrLen
456 && (memcmp(attr, curAttr, attrLen*SIZEOF_CHAR/*sizeof(char16_t)*/) == 0)) {
457 if (ns == null) {
458 if (curNs == null) {
459 if (kDebugStringPoolNoisy) {
460 ALOGI(" FOUND!");
461 }
462 return i;
463 }
464 } else if (curNs != null) {
465 //printf(" -. ns=%s, curNs=%s\n",
466 // String8(ns).string(), String8(curNs).string());
467 if (memcmp(ns, curNs, nsLen*SIZEOF_CHAR/*sizeof(char16_t)*/) == 0) {
468 if (kDebugStringPoolNoisy) {
469 ALOGI(" FOUND!");
470 }
471 return i;
472 }
473 }
474 }
475 }
476 }
477 }
478
479 return NAME_NOT_FOUND;
480 }
481
memcmp(String s1, String s2, int len)482 private int memcmp(String s1, String s2, int len) {
483 for (int i = 0; i < len; i++) {
484 int d = s1.charAt(i) - s2.charAt(i);
485 if (d != 0) {
486 return d;
487 }
488 }
489 return 0;
490 }
491
indexOfID()492 public int indexOfID()
493 {
494 if (mEventCode == START_TAG) {
495 final int idx = dtohs(new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt).idIndex);
496 if (idx > 0) return (idx-1);
497 }
498 return NAME_NOT_FOUND;
499 }
500
indexOfClass()501 public int indexOfClass()
502 {
503 if (mEventCode == START_TAG) {
504 final int idx = dtohs(new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt).classIndex);
505 if (idx > 0) return (idx-1);
506 }
507 return NAME_NOT_FOUND;
508 }
509
indexOfStyle()510 public int indexOfStyle()
511 {
512 if (mEventCode == START_TAG) {
513 final int idx = dtohs(new ResXMLTree_attrExt(mTree.mBuffer.buf, mCurExt).styleIndex);
514 if (idx > 0) return (idx-1);
515 }
516 return NAME_NOT_FOUND;
517 }
518
nextNode()519 int nextNode() {
520 if (mEventCode < 0) {
521 return mEventCode;
522 }
523
524 do {
525 int nextOffset = mCurNode.myOffset() + dtohl(mCurNode.header.size);
526 if (nextOffset >= mTree.mDataLen) {
527 mCurNode = null;
528 return (mEventCode=END_DOCUMENT);
529 }
530
531 // final ResXMLTree_node next = (ResXMLTree_node)
532 // (((final int8_t*)mCurNode) + dtohl(mCurNode.header.size));
533 ResXMLTree_node next = new ResXMLTree_node(mTree.mBuffer.buf, nextOffset);
534 if (kDebugXMLNoisy) {
535 ALOGI("Next node: prev=%s, next=%s\n", mCurNode, next);
536 }
537
538 if (next.myOffset() >= mTree.mDataLen) {
539 mCurNode = null;
540 return (mEventCode=END_DOCUMENT);
541 }
542
543 if (mTree.validateNode(next) != NO_ERROR) {
544 mCurNode = null;
545 return (mEventCode=BAD_DOCUMENT);
546 }
547
548 mCurNode = next;
549 final int headerSize = dtohs(next.header.headerSize);
550 final int totalSize = dtohl(next.header.size);
551 mCurExt = next.myOffset() + headerSize;
552 int minExtSize = 0;
553 int eventCode = dtohs(next.header.type);
554 switch ((mEventCode=eventCode)) {
555 case RES_XML_START_NAMESPACE_TYPE:
556 case RES_XML_END_NAMESPACE_TYPE:
557 minExtSize = SIZEOF_RESXMLTREE_NAMESPACE_EXT /*sizeof(ResXMLTree_namespaceExt)*/;
558 break;
559 case RES_XML_START_ELEMENT_TYPE:
560 minExtSize = SIZEOF_RESXMLTREE_ATTR_EXT /*sizeof(ResXMLTree_attrExt)*/;
561 break;
562 case RES_XML_END_ELEMENT_TYPE:
563 minExtSize = ResXMLTree_endElementExt.SIZEOF /*sizeof(ResXMLTree_endElementExt)*/;
564 break;
565 case RES_XML_CDATA_TYPE:
566 minExtSize = SIZEOF_RESXMLTREE_CDATA_EXT /*sizeof(ResXMLTree_cdataExt)*/;
567 break;
568 default:
569 ALOGW("Unknown XML block: header type %d in node at %d\n",
570 (int)dtohs(next.header.type),
571 (next.myOffset()-mTree.mHeader.myOffset()));
572 continue;
573 }
574
575 if ((totalSize-headerSize) < minExtSize) {
576 ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
577 (int)dtohs(next.header.type),
578 (next.myOffset()-mTree.mHeader.myOffset()),
579 (int)(totalSize-headerSize), (int)minExtSize);
580 return (mEventCode=BAD_DOCUMENT);
581 }
582
583 //printf("CurNode=%s, CurExt=%s, headerSize=%d, minExtSize=%d\n",
584 // mCurNode, mCurExt, headerSize, minExtSize);
585
586 return eventCode;
587 } while (true);
588 }
589
getPosition(ResXMLPosition pos)590 void getPosition(ResXMLPosition pos)
591 {
592 pos.eventCode = mEventCode;
593 pos.curNode = mCurNode;
594 pos.curExt = mCurExt;
595 }
596
setPosition(final ResXMLPosition pos)597 void setPosition(final ResXMLPosition pos)
598 {
599 mEventCode = pos.eventCode;
600 mCurNode = pos.curNode;
601 mCurExt = pos.curExt;
602 }
603
setSourceResourceId(int resId)604 public void setSourceResourceId(int resId) {
605 mSourceResourceId = resId;
606 }
607
getSourceResourceId()608 public int getSourceResourceId() {
609 return mSourceResourceId;
610 }
611
612 static class ResXMLPosition
613 {
614 int eventCode;
615 ResXMLTree_node curNode;
616 int curExt;
617 };
618 }
619