Home | History | Annotate | Download | only in android
      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 
     63   public ResXMLParser(ResXMLTree tree) {
     64     this.mTree = tree;
     65     this.mEventCode = BAD_DOCUMENT;
     66   }
     67 
     68   public void restart() {
     69     mCurNode = null;
     70     mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
     71   }
     72 
     73   public ResStringPool getStrings() {
     74     return mTree.mStrings;
     75   }
     76 
     77   int getEventType()
     78   {
     79     return mEventCode;
     80   }
     81 
     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 
     94   int getCommentID()
     95   {
     96     return mCurNode != null ? dtohl(mCurNode.comment.index) : -1;
     97   }
     98 
     99 final String getComment(Ref<Integer> outLen)
    100   {
    101     int id = getCommentID();
    102     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
    103   }
    104 
    105   public int getLineNumber()
    106   {
    107     return mCurNode != null ? dtohl(mCurNode.lineNumber) : -1;
    108   }
    109 
    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 
    118 final String getText(Ref<Integer> outLen)
    119   {
    120     int id = getTextID();
    121     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
    122   }
    123 
    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 
    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 
    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 
    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 
    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 
    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 
    174 final String getElementNamespace(Ref<Integer> outLen)
    175   {
    176     int id = getElementNamespaceID();
    177     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
    178   }
    179 
    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 
    191 final String getElementName(Ref<Integer> outLen)
    192   {
    193     int id = getElementNameID();
    194     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : null;
    195   }
    196 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    589   void getPosition(ResXMLPosition pos)
    590   {
    591     pos.eventCode = mEventCode;
    592     pos.curNode = mCurNode;
    593     pos.curExt = mCurExt;
    594   }
    595 
    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