1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.res; 18 19 import static android.content.res.Resources.ID_NULL; 20 import static android.system.OsConstants.EINVAL; 21 22 import android.annotation.AnyRes; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.os.Build; 27 import android.util.TypedValue; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.util.XmlUtils; 31 32 import dalvik.annotation.optimization.CriticalNative; 33 import dalvik.annotation.optimization.FastNative; 34 35 import org.xmlpull.v1.XmlPullParserException; 36 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.io.Reader; 40 41 /** 42 * Wrapper around a compiled XML file. 43 * 44 * {@hide} 45 */ 46 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 47 public final class XmlBlock implements AutoCloseable { 48 private static final boolean DEBUG=false; 49 50 @UnsupportedAppUsage XmlBlock(byte[] data)51 public XmlBlock(byte[] data) { 52 mAssets = null; 53 mNative = nativeCreate(data, 0, data.length); 54 mStrings = new StringBlock(nativeGetStringBlock(mNative), false); 55 } 56 XmlBlock(byte[] data, int offset, int size)57 public XmlBlock(byte[] data, int offset, int size) { 58 mAssets = null; 59 mNative = nativeCreate(data, offset, size); 60 mStrings = new StringBlock(nativeGetStringBlock(mNative), false); 61 } 62 63 @Override close()64 public void close() { 65 synchronized (this) { 66 if (mOpen) { 67 mOpen = false; 68 decOpenCountLocked(); 69 } 70 } 71 } 72 decOpenCountLocked()73 private void decOpenCountLocked() { 74 mOpenCount--; 75 if (mOpenCount == 0) { 76 mStrings.close(); 77 nativeDestroy(mNative); 78 mNative = 0; 79 if (mAssets != null) { 80 mAssets.xmlBlockGone(hashCode()); 81 } 82 } 83 } 84 85 @UnsupportedAppUsage newParser()86 public XmlResourceParser newParser() { 87 return newParser(ID_NULL); 88 } 89 newParser(@nyRes int resId)90 public XmlResourceParser newParser(@AnyRes int resId) { 91 synchronized (this) { 92 if (mNative != 0) { 93 return new Parser(nativeCreateParseState(mNative, resId), this); 94 } 95 return null; 96 } 97 } 98 99 /** 100 * Returns a XmlResourceParser that validates the xml using the given validator. 101 */ newParser(@nyRes int resId, Validator validator)102 public XmlResourceParser newParser(@AnyRes int resId, Validator validator) { 103 synchronized (this) { 104 if (mNative != 0) { 105 return new Parser(nativeCreateParseState(mNative, resId), this, validator); 106 } 107 return null; 108 } 109 } 110 111 /** 112 * Reference Error.h UNEXPECTED_NULL 113 */ 114 private static final int ERROR_NULL_DOCUMENT = Integer.MIN_VALUE + 8; 115 /** 116 * The reason not to ResXMLParser::BAD_DOCUMENT which is -1 is that other places use the same 117 * value. Reference Error.h BAD_VALUE = -EINVAL 118 */ 119 private static final int ERROR_BAD_DOCUMENT = -EINVAL; 120 121 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 122 public final class Parser implements XmlResourceParser { 123 Validator mValidator; 124 Parser(long parseState, XmlBlock block)125 Parser(long parseState, XmlBlock block) { 126 mParseState = parseState; 127 mBlock = block; 128 block.mOpenCount++; 129 } 130 Parser(long parseState, XmlBlock block, Validator validator)131 Parser(long parseState, XmlBlock block, Validator validator) { 132 this(parseState, block); 133 mValidator = validator; 134 } 135 136 @AnyRes getSourceResId()137 public int getSourceResId() { 138 return nativeGetSourceResId(mParseState); 139 } 140 setFeature(String name, boolean state)141 public void setFeature(String name, boolean state) throws XmlPullParserException { 142 if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) { 143 return; 144 } 145 if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) { 146 return; 147 } 148 throw new XmlPullParserException("Unsupported feature: " + name); 149 } getFeature(String name)150 public boolean getFeature(String name) { 151 if (FEATURE_PROCESS_NAMESPACES.equals(name)) { 152 return true; 153 } 154 if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { 155 return true; 156 } 157 return false; 158 } setProperty(String name, Object value)159 public void setProperty(String name, Object value) throws XmlPullParserException { 160 throw new XmlPullParserException("setProperty() not supported"); 161 } getProperty(String name)162 public Object getProperty(String name) { 163 return null; 164 } setInput(Reader in)165 public void setInput(Reader in) throws XmlPullParserException { 166 throw new XmlPullParserException("setInput() not supported"); 167 } setInput(InputStream inputStream, String inputEncoding)168 public void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException { 169 throw new XmlPullParserException("setInput() not supported"); 170 } defineEntityReplacementText(String entityName, String replacementText)171 public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException { 172 throw new XmlPullParserException("defineEntityReplacementText() not supported"); 173 } getNamespacePrefix(int pos)174 public String getNamespacePrefix(int pos) throws XmlPullParserException { 175 throw new XmlPullParserException("getNamespacePrefix() not supported"); 176 } getInputEncoding()177 public String getInputEncoding() { 178 return null; 179 } getNamespace(String prefix)180 public String getNamespace(String prefix) { 181 throw new RuntimeException("getNamespace() not supported"); 182 } getNamespaceCount(int depth)183 public int getNamespaceCount(int depth) throws XmlPullParserException { 184 throw new XmlPullParserException("getNamespaceCount() not supported"); 185 } getPositionDescription()186 public String getPositionDescription() { 187 return "Binary XML file line #" + getLineNumber(); 188 } getNamespaceUri(int pos)189 public String getNamespaceUri(int pos) throws XmlPullParserException { 190 throw new XmlPullParserException("getNamespaceUri() not supported"); 191 } getColumnNumber()192 public int getColumnNumber() { 193 return -1; 194 } getDepth()195 public int getDepth() { 196 return mDepth; 197 } 198 @Nullable getText()199 public String getText() { 200 int id = nativeGetText(mParseState); 201 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 202 } getLineNumber()203 public int getLineNumber() { 204 final int lineNumber = nativeGetLineNumber(mParseState); 205 if (lineNumber == ERROR_NULL_DOCUMENT) { 206 throw new NullPointerException("Null document"); 207 } 208 return lineNumber; 209 } getEventType()210 public int getEventType() throws XmlPullParserException { 211 return mEventType; 212 } isWhitespace()213 public boolean isWhitespace() throws XmlPullParserException { 214 // whitespace was stripped by aapt. 215 return false; 216 } getPrefix()217 public String getPrefix() { 218 throw new RuntimeException("getPrefix not supported"); 219 } getTextCharacters(int[] holderForStartAndLength)220 public char[] getTextCharacters(int[] holderForStartAndLength) { 221 String txt = getText(); 222 char[] chars = null; 223 if (txt != null) { 224 holderForStartAndLength[0] = 0; 225 holderForStartAndLength[1] = txt.length(); 226 chars = new char[txt.length()]; 227 txt.getChars(0, txt.length(), chars, 0); 228 } 229 return chars; 230 } 231 @Nullable getNamespace()232 public String getNamespace() { 233 int id = nativeGetNamespace(mParseState); 234 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : ""; 235 } 236 @Nullable getName()237 public String getName() { 238 int id = nativeGetName(mParseState); 239 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 240 } 241 @NonNull getAttributeNamespace(int index)242 public String getAttributeNamespace(int index) { 243 final int id = nativeGetAttributeNamespace(mParseState, index); 244 if (id == ERROR_NULL_DOCUMENT) { 245 throw new NullPointerException("Null document"); 246 } 247 if (DEBUG) System.out.println("getAttributeNamespace of " + index + " = " + id); 248 if (id >= 0) return getSequenceString(mStrings.getSequence(id)); 249 else if (id == -1) return ""; 250 throw new IndexOutOfBoundsException(String.valueOf(index)); 251 } 252 @NonNull getAttributeName(int index)253 public String getAttributeName(int index) { 254 final int id = nativeGetAttributeName(mParseState, index); 255 if (DEBUG) System.out.println("getAttributeName of " + index + " = " + id); 256 if (id == ERROR_NULL_DOCUMENT) { 257 throw new NullPointerException("Null document"); 258 } 259 if (id >= 0) return getSequenceString(mStrings.getSequence(id)); 260 throw new IndexOutOfBoundsException(String.valueOf(index)); 261 } getAttributePrefix(int index)262 public String getAttributePrefix(int index) { 263 throw new RuntimeException("getAttributePrefix not supported"); 264 } isEmptyElementTag()265 public boolean isEmptyElementTag() throws XmlPullParserException { 266 // XXX Need to detect this. 267 return false; 268 } getAttributeCount()269 public int getAttributeCount() { 270 if (mEventType == START_TAG) { 271 final int count = nativeGetAttributeCount(mParseState); 272 if (count == ERROR_NULL_DOCUMENT) { 273 throw new NullPointerException("Null document"); 274 } 275 return count; 276 } else { 277 return -1; 278 } 279 } 280 @NonNull getAttributeValue(int index)281 public String getAttributeValue(int index) { 282 final int id = nativeGetAttributeStringValue(mParseState, index); 283 if (id == ERROR_NULL_DOCUMENT) { 284 throw new NullPointerException("Null document"); 285 } 286 if (DEBUG) System.out.println("getAttributeValue of " + index + " = " + id); 287 if (id >= 0) return getSequenceString(mStrings.getSequence(id)); 288 289 // May be some other type... check and try to convert if so. 290 final int t = nativeGetAttributeDataType(mParseState, index); 291 if (t == ERROR_NULL_DOCUMENT) { 292 throw new NullPointerException("Null document"); 293 } 294 if (t == TypedValue.TYPE_NULL) { 295 throw new IndexOutOfBoundsException(String.valueOf(index)); 296 } 297 298 final int v = nativeGetAttributeData(mParseState, index); 299 if (v == ERROR_NULL_DOCUMENT) { 300 throw new NullPointerException("Null document"); 301 } 302 return TypedValue.coerceToString(t, v); 303 } getAttributeType(int index)304 public String getAttributeType(int index) { 305 return "CDATA"; 306 } isAttributeDefault(int index)307 public boolean isAttributeDefault(int index) { 308 return false; 309 } nextToken()310 public int nextToken() throws XmlPullParserException,IOException { 311 return next(); 312 } getAttributeValue(String namespace, String name)313 public String getAttributeValue(String namespace, String name) { 314 int idx = nativeGetAttributeIndex(mParseState, namespace, name); 315 if (idx >= 0) { 316 if (DEBUG) System.out.println("getAttributeName of " 317 + namespace + ":" + name + " index = " + idx); 318 if (DEBUG) System.out.println( 319 "Namespace=" + getAttributeNamespace(idx) 320 + "Name=" + getAttributeName(idx) 321 + ", Value=" + getAttributeValue(idx)); 322 String value = getAttributeValue(idx); 323 if (mValidator != null) { 324 mValidator.validateStrAttr(this, name, value); 325 } 326 return value; 327 } 328 return null; 329 } next()330 public int next() throws XmlPullParserException,IOException { 331 if (!mStarted) { 332 mStarted = true; 333 return START_DOCUMENT; 334 } 335 if (mParseState == 0) { 336 return END_DOCUMENT; 337 } 338 int ev = nativeNext(mParseState); 339 if (ev == ERROR_BAD_DOCUMENT) { 340 throw new XmlPullParserException("Corrupt XML binary file"); 341 } 342 if (mDecNextDepth) { 343 mDepth--; 344 mDecNextDepth = false; 345 } 346 switch (ev) { 347 case START_TAG: 348 mDepth++; 349 break; 350 case END_TAG: 351 mDecNextDepth = true; 352 break; 353 } 354 mEventType = ev; 355 if (mValidator != null) { 356 mValidator.validate(this); 357 } 358 if (ev == END_DOCUMENT) { 359 // Automatically close the parse when we reach the end of 360 // a document, since the standard XmlPullParser interface 361 // doesn't have such an API so most clients will leave us 362 // dangling. 363 close(); 364 } 365 return ev; 366 } require(int type, String namespace, String name)367 public void require(int type, String namespace, String name) throws XmlPullParserException,IOException { 368 if (type != getEventType() 369 || (namespace != null && !namespace.equals( getNamespace () ) ) 370 || (name != null && !name.equals( getName() ) ) ) 371 throw new XmlPullParserException( "expected "+ TYPES[ type ]+getPositionDescription()); 372 } nextText()373 public String nextText() throws XmlPullParserException,IOException { 374 if(getEventType() != START_TAG) { 375 throw new XmlPullParserException( 376 getPositionDescription() 377 + ": parser must be on START_TAG to read next text", this, null); 378 } 379 int eventType = next(); 380 if(eventType == TEXT) { 381 String result = getText(); 382 eventType = next(); 383 if(eventType != END_TAG) { 384 throw new XmlPullParserException( 385 getPositionDescription() 386 + ": event TEXT it must be immediately followed by END_TAG", this, null); 387 } 388 return result; 389 } else if(eventType == END_TAG) { 390 return ""; 391 } else { 392 throw new XmlPullParserException( 393 getPositionDescription() 394 + ": parser must be on START_TAG or TEXT to read text", this, null); 395 } 396 } nextTag()397 public int nextTag() throws XmlPullParserException,IOException { 398 int eventType = next(); 399 if(eventType == TEXT && isWhitespace()) { // skip whitespace 400 eventType = next(); 401 } 402 if (eventType != START_TAG && eventType != END_TAG) { 403 throw new XmlPullParserException( 404 getPositionDescription() 405 + ": expected start or end tag", this, null); 406 } 407 return eventType; 408 } 409 getAttributeNameResource(int index)410 public int getAttributeNameResource(int index) { 411 final int resourceNameId = nativeGetAttributeResource(mParseState, index); 412 if (resourceNameId == ERROR_NULL_DOCUMENT) { 413 throw new NullPointerException("Null document"); 414 } 415 return resourceNameId; 416 } 417 getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue)418 public int getAttributeListValue(String namespace, String attribute, 419 String[] options, int defaultValue) { 420 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 421 if (idx >= 0) { 422 return getAttributeListValue(idx, options, defaultValue); 423 } 424 return defaultValue; 425 } getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue)426 public boolean getAttributeBooleanValue(String namespace, String attribute, 427 boolean defaultValue) { 428 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 429 if (idx >= 0) { 430 return getAttributeBooleanValue(idx, defaultValue); 431 } 432 return defaultValue; 433 } getAttributeResourceValue(String namespace, String attribute, int defaultValue)434 public int getAttributeResourceValue(String namespace, String attribute, 435 int defaultValue) { 436 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 437 if (idx >= 0) { 438 return getAttributeResourceValue(idx, defaultValue); 439 } 440 return defaultValue; 441 } getAttributeIntValue(String namespace, String attribute, int defaultValue)442 public int getAttributeIntValue(String namespace, String attribute, 443 int defaultValue) { 444 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 445 if (idx >= 0) { 446 return getAttributeIntValue(idx, defaultValue); 447 } 448 return defaultValue; 449 } getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue)450 public int getAttributeUnsignedIntValue(String namespace, String attribute, 451 int defaultValue) 452 { 453 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 454 if (idx >= 0) { 455 return getAttributeUnsignedIntValue(idx, defaultValue); 456 } 457 return defaultValue; 458 } getAttributeFloatValue(String namespace, String attribute, float defaultValue)459 public float getAttributeFloatValue(String namespace, String attribute, 460 float defaultValue) { 461 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 462 if (idx >= 0) { 463 return getAttributeFloatValue(idx, defaultValue); 464 } 465 return defaultValue; 466 } 467 getAttributeListValue(int idx, String[] options, int defaultValue)468 public int getAttributeListValue(int idx, 469 String[] options, int defaultValue) { 470 final int t = nativeGetAttributeDataType(mParseState, idx); 471 if (t == ERROR_NULL_DOCUMENT) { 472 throw new NullPointerException("Null document"); 473 } 474 final int v = nativeGetAttributeData(mParseState, idx); 475 if (v == ERROR_NULL_DOCUMENT) { 476 throw new NullPointerException("Null document"); 477 } 478 if (t == TypedValue.TYPE_STRING) { 479 return XmlUtils.convertValueToList( 480 mStrings.getSequence(v), options, defaultValue); 481 } 482 return v; 483 } getAttributeBooleanValue(int idx, boolean defaultValue)484 public boolean getAttributeBooleanValue(int idx, 485 boolean defaultValue) { 486 final int t = nativeGetAttributeDataType(mParseState, idx); 487 if (t == ERROR_NULL_DOCUMENT) { 488 throw new NullPointerException("Null document"); 489 } 490 // Note: don't attempt to convert any other types, because 491 // we want to count on aapt doing the conversion for us. 492 if (t >= TypedValue.TYPE_FIRST_INT && t <= TypedValue.TYPE_LAST_INT) { 493 final int v = nativeGetAttributeData(mParseState, idx); 494 if (v == ERROR_NULL_DOCUMENT) { 495 throw new NullPointerException("Null document"); 496 } 497 return v != 0; 498 } 499 return defaultValue; 500 } getAttributeResourceValue(int idx, int defaultValue)501 public int getAttributeResourceValue(int idx, int defaultValue) { 502 final int t = nativeGetAttributeDataType(mParseState, idx); 503 if (t == ERROR_NULL_DOCUMENT) { 504 throw new NullPointerException("Null document"); 505 } 506 // Note: don't attempt to convert any other types, because 507 // we want to count on aapt doing the conversion for us. 508 if (t == TypedValue.TYPE_REFERENCE) { 509 final int v = nativeGetAttributeData(mParseState, idx); 510 if (v == ERROR_NULL_DOCUMENT) { 511 throw new NullPointerException("Null document"); 512 } 513 return v; 514 } 515 return defaultValue; 516 } getAttributeIntValue(int idx, int defaultValue)517 public int getAttributeIntValue(int idx, int defaultValue) { 518 final int t = nativeGetAttributeDataType(mParseState, idx); 519 if (t == ERROR_NULL_DOCUMENT) { 520 throw new NullPointerException("Null document"); 521 } 522 // Note: don't attempt to convert any other types, because 523 // we want to count on aapt doing the conversion for us. 524 if (t >= TypedValue.TYPE_FIRST_INT && t <= TypedValue.TYPE_LAST_INT) { 525 final int v = nativeGetAttributeData(mParseState, idx); 526 if (v == ERROR_NULL_DOCUMENT) { 527 throw new NullPointerException("Null document"); 528 } 529 return v; 530 } 531 return defaultValue; 532 } getAttributeUnsignedIntValue(int idx, int defaultValue)533 public int getAttributeUnsignedIntValue(int idx, int defaultValue) { 534 int t = nativeGetAttributeDataType(mParseState, idx); 535 if (t == ERROR_NULL_DOCUMENT) { 536 throw new NullPointerException("Null document"); 537 } 538 // Note: don't attempt to convert any other types, because 539 // we want to count on aapt doing the conversion for us. 540 if (t >= TypedValue.TYPE_FIRST_INT && t <= TypedValue.TYPE_LAST_INT) { 541 final int v = nativeGetAttributeData(mParseState, idx); 542 if (v == ERROR_NULL_DOCUMENT) { 543 throw new NullPointerException("Null document"); 544 } 545 return v; 546 } 547 return defaultValue; 548 } getAttributeFloatValue(int idx, float defaultValue)549 public float getAttributeFloatValue(int idx, float defaultValue) { 550 final int t = nativeGetAttributeDataType(mParseState, idx); 551 if (t == ERROR_NULL_DOCUMENT) { 552 throw new NullPointerException("Null document"); 553 } 554 // Note: don't attempt to convert any other types, because 555 // we want to count on aapt doing the conversion for us. 556 if (t == TypedValue.TYPE_FLOAT) { 557 final int v = nativeGetAttributeData(mParseState, idx); 558 if (v == ERROR_NULL_DOCUMENT) { 559 throw new NullPointerException("Null document"); 560 } 561 return Float.intBitsToFloat(v); 562 } 563 throw new RuntimeException("not a float!"); 564 } 565 @Nullable getIdAttribute()566 public String getIdAttribute() { 567 final int id = nativeGetIdAttribute(mParseState); 568 if (id == ERROR_NULL_DOCUMENT) { 569 throw new NullPointerException("Null document"); 570 } 571 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 572 } 573 @Nullable getClassAttribute()574 public String getClassAttribute() { 575 final int id = nativeGetClassAttribute(mParseState); 576 if (id == ERROR_NULL_DOCUMENT) { 577 throw new NullPointerException("Null document"); 578 } 579 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 580 } 581 getIdAttributeResourceValue(int defaultValue)582 public int getIdAttributeResourceValue(int defaultValue) { 583 //todo: create and use native method 584 return getAttributeResourceValue(null, "id", defaultValue); 585 } 586 getStyleAttribute()587 public int getStyleAttribute() { 588 final int styleAttributeId = nativeGetStyleAttribute(mParseState); 589 if (styleAttributeId == ERROR_NULL_DOCUMENT) { 590 throw new NullPointerException("Null document"); 591 } 592 return styleAttributeId; 593 } 594 getSequenceString(@ullable CharSequence str)595 private String getSequenceString(@Nullable CharSequence str) { 596 if (str == null) { 597 // A value of null retrieved from a StringPool indicates that retrieval of the 598 // string failed due to incremental installation. The presence of all the XmlBlock 599 // data is verified when it is created, so this exception must not be possible. 600 throw new IllegalStateException("Retrieving a string from the StringPool of an" 601 + " XmlBlock should never fail"); 602 } 603 return str.toString(); 604 } 605 close()606 public void close() { 607 synchronized (mBlock) { 608 if (mParseState != 0) { 609 nativeDestroyParseState(mParseState); 610 mParseState = 0; 611 mBlock.decOpenCountLocked(); 612 } 613 } 614 } 615 finalize()616 protected void finalize() throws Throwable { 617 close(); 618 } 619 620 @Nullable getPooledString(int id)621 /*package*/ final CharSequence getPooledString(int id) { 622 return mStrings.getSequence(id); 623 } 624 625 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 626 /*package*/ long mParseState; 627 @UnsupportedAppUsage 628 private final XmlBlock mBlock; 629 private boolean mStarted = false; 630 private boolean mDecNextDepth = false; 631 private int mDepth = 0; 632 private int mEventType = START_DOCUMENT; 633 } 634 finalize()635 protected void finalize() throws Throwable { 636 close(); 637 } 638 639 /** 640 * Create from an existing xml block native object. This is 641 * -extremely- dangerous -- only use it if you absolutely know what you 642 * are doing! The given native object must exist for the entire lifetime 643 * of this newly creating XmlBlock. 644 */ XmlBlock(@ullable AssetManager assets, long xmlBlock)645 XmlBlock(@Nullable AssetManager assets, long xmlBlock) { 646 mAssets = assets; 647 mNative = xmlBlock; 648 mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false); 649 } 650 651 private @Nullable final AssetManager mAssets; 652 private long mNative; // final, but gets reset on close 653 /*package*/ final StringBlock mStrings; 654 private boolean mOpen = true; 655 private int mOpenCount = 1; 656 nativeCreate(byte[] data, int offset, int size)657 private static final native long nativeCreate(byte[] data, 658 int offset, 659 int size); nativeGetStringBlock(long obj)660 private static final native long nativeGetStringBlock(long obj); nativeCreateParseState(long obj, int resId)661 private static final native long nativeCreateParseState(long obj, int resId); nativeDestroyParseState(long state)662 private static final native void nativeDestroyParseState(long state); nativeDestroy(long obj)663 private static final native void nativeDestroy(long obj); 664 665 // ----------- @FastNative ------------------ 666 667 @FastNative nativeGetAttributeIndex( long state, String namespace, String name)668 private static native int nativeGetAttributeIndex( 669 long state, String namespace, String name); 670 671 // ----------- @CriticalNative ------------------ 672 @CriticalNative nativeNext(long state)673 /*package*/ static final native int nativeNext(long state); 674 675 @CriticalNative nativeGetNamespace(long state)676 private static final native int nativeGetNamespace(long state); 677 678 @CriticalNative nativeGetName(long state)679 /*package*/ static final native int nativeGetName(long state); 680 681 @CriticalNative nativeGetText(long state)682 private static final native int nativeGetText(long state); 683 684 @CriticalNative nativeGetLineNumber(long state)685 private static final native int nativeGetLineNumber(long state); 686 687 @CriticalNative nativeGetAttributeCount(long state)688 private static final native int nativeGetAttributeCount(long state); 689 690 @CriticalNative nativeGetAttributeNamespace(long state, int idx)691 private static final native int nativeGetAttributeNamespace(long state, int idx); 692 693 @CriticalNative nativeGetAttributeName(long state, int idx)694 private static final native int nativeGetAttributeName(long state, int idx); 695 696 @CriticalNative nativeGetAttributeResource(long state, int idx)697 private static final native int nativeGetAttributeResource(long state, int idx); 698 699 @CriticalNative nativeGetAttributeDataType(long state, int idx)700 private static final native int nativeGetAttributeDataType(long state, int idx); 701 702 @CriticalNative nativeGetAttributeData(long state, int idx)703 private static final native int nativeGetAttributeData(long state, int idx); 704 705 @CriticalNative nativeGetAttributeStringValue(long state, int idx)706 private static final native int nativeGetAttributeStringValue(long state, int idx); 707 708 @CriticalNative nativeGetIdAttribute(long state)709 private static final native int nativeGetIdAttribute(long state); 710 711 @CriticalNative nativeGetClassAttribute(long state)712 private static final native int nativeGetClassAttribute(long state); 713 714 @CriticalNative nativeGetStyleAttribute(long state)715 private static final native int nativeGetStyleAttribute(long state); 716 717 @CriticalNative nativeGetSourceResId(long state)718 private static final native int nativeGetSourceResId(long state); 719 } 720