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