• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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