• 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   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