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