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