• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.util.TypedValue;
20 import com.android.internal.util.XmlUtils;
21 
22 import org.xmlpull.v1.XmlPullParserException;
23 
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.Reader;
27 
28 /**
29  * Wrapper around a compiled XML file.
30  *
31  * {@hide}
32  */
33 final class XmlBlock {
34     private static final boolean DEBUG=false;
35 
XmlBlock(byte[] data)36     public XmlBlock(byte[] data) {
37         mAssets = null;
38         mNative = nativeCreate(data, 0, data.length);
39         mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
40     }
41 
XmlBlock(byte[] data, int offset, int size)42     public XmlBlock(byte[] data, int offset, int size) {
43         mAssets = null;
44         mNative = nativeCreate(data, offset, size);
45         mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
46     }
47 
close()48     public void close() {
49         synchronized (this) {
50             if (mOpen) {
51                 mOpen = false;
52                 decOpenCountLocked();
53             }
54         }
55     }
56 
decOpenCountLocked()57     private void decOpenCountLocked() {
58         mOpenCount--;
59         if (mOpenCount == 0) {
60             nativeDestroy(mNative);
61             if (mAssets != null) {
62                 mAssets.xmlBlockGone();
63             }
64         }
65     }
66 
newParser()67     public XmlResourceParser newParser() {
68         synchronized (this) {
69             if (mNative != 0) {
70                 return new Parser(nativeCreateParseState(mNative), this);
71             }
72             return null;
73         }
74     }
75 
76     /*package*/ final class Parser implements XmlResourceParser {
Parser(int parseState, XmlBlock block)77         Parser(int parseState, XmlBlock block) {
78             mParseState = parseState;
79             mBlock = block;
80             block.mOpenCount++;
81         }
82 
setFeature(String name, boolean state)83         public void setFeature(String name, boolean state) throws XmlPullParserException {
84             if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
85                 return;
86             }
87             if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) {
88                 return;
89             }
90             throw new XmlPullParserException("Unsupported feature: " + name);
91         }
getFeature(String name)92         public boolean getFeature(String name) {
93             if (FEATURE_PROCESS_NAMESPACES.equals(name)) {
94                 return true;
95             }
96             if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
97                 return true;
98             }
99             return false;
100         }
setProperty(String name, Object value)101         public void setProperty(String name, Object value) throws XmlPullParserException {
102             throw new XmlPullParserException("setProperty() not supported");
103         }
getProperty(String name)104         public Object getProperty(String name) {
105             return null;
106         }
setInput(Reader in)107         public void setInput(Reader in) throws XmlPullParserException {
108             throw new XmlPullParserException("setInput() not supported");
109         }
setInput(InputStream inputStream, String inputEncoding)110         public void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException {
111             throw new XmlPullParserException("setInput() not supported");
112         }
defineEntityReplacementText(String entityName, String replacementText)113         public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException {
114             throw new XmlPullParserException("defineEntityReplacementText() not supported");
115         }
getNamespacePrefix(int pos)116         public String getNamespacePrefix(int pos) throws XmlPullParserException {
117             throw new XmlPullParserException("getNamespacePrefix() not supported");
118         }
getInputEncoding()119         public String getInputEncoding() {
120             return null;
121         }
getNamespace(String prefix)122         public String getNamespace(String prefix) {
123             throw new RuntimeException("getNamespace() not supported");
124         }
getNamespaceCount(int depth)125         public int getNamespaceCount(int depth) throws XmlPullParserException {
126             throw new XmlPullParserException("getNamespaceCount() not supported");
127         }
getPositionDescription()128         public String getPositionDescription() {
129             return "Binary XML file line #" + getLineNumber();
130         }
getNamespaceUri(int pos)131         public String getNamespaceUri(int pos) throws XmlPullParserException {
132             throw new XmlPullParserException("getNamespaceUri() not supported");
133         }
getColumnNumber()134         public int getColumnNumber() {
135             return -1;
136         }
getDepth()137         public int getDepth() {
138             return mDepth;
139         }
getText()140         public String getText() {
141             int id = nativeGetText(mParseState);
142             return id >= 0 ? mStrings.get(id).toString() : null;
143         }
getLineNumber()144         public int getLineNumber() {
145             return nativeGetLineNumber(mParseState);
146         }
getEventType()147         public int getEventType() throws XmlPullParserException {
148             return mEventType;
149         }
isWhitespace()150         public boolean isWhitespace() throws XmlPullParserException {
151             // whitespace was stripped by aapt.
152             return false;
153         }
getPrefix()154         public String getPrefix() {
155             throw new RuntimeException("getPrefix not supported");
156         }
getTextCharacters(int[] holderForStartAndLength)157         public char[] getTextCharacters(int[] holderForStartAndLength) {
158             String txt = getText();
159             char[] chars = null;
160             if (txt != null) {
161                 holderForStartAndLength[0] = 0;
162                 holderForStartAndLength[1] = txt.length();
163                 chars = new char[txt.length()];
164                 txt.getChars(0, txt.length(), chars, 0);
165             }
166             return chars;
167         }
getNamespace()168         public String getNamespace() {
169             int id = nativeGetNamespace(mParseState);
170             return id >= 0 ? mStrings.get(id).toString() : "";
171         }
getName()172         public String getName() {
173             int id = nativeGetName(mParseState);
174             return id >= 0 ? mStrings.get(id).toString() : null;
175         }
getAttributeNamespace(int index)176         public String getAttributeNamespace(int index) {
177             int id = nativeGetAttributeNamespace(mParseState, index);
178             if (DEBUG) System.out.println("getAttributeNamespace of " + index + " = " + id);
179             if (id >= 0) return mStrings.get(id).toString();
180             else if (id == -1) return "";
181             throw new IndexOutOfBoundsException(String.valueOf(index));
182         }
getAttributeName(int index)183         public String getAttributeName(int index) {
184             int id = nativeGetAttributeName(mParseState, index);
185             if (DEBUG) System.out.println("getAttributeName of " + index + " = " + id);
186             if (id >= 0) return mStrings.get(id).toString();
187             throw new IndexOutOfBoundsException(String.valueOf(index));
188         }
getAttributePrefix(int index)189         public String getAttributePrefix(int index) {
190             throw new RuntimeException("getAttributePrefix not supported");
191         }
isEmptyElementTag()192         public boolean isEmptyElementTag() throws XmlPullParserException {
193             // XXX Need to detect this.
194             return false;
195         }
getAttributeCount()196         public int getAttributeCount() {
197             return mEventType == START_TAG ? nativeGetAttributeCount(mParseState) : -1;
198         }
getAttributeValue(int index)199         public String getAttributeValue(int index) {
200             int id = nativeGetAttributeStringValue(mParseState, index);
201             if (DEBUG) System.out.println("getAttributeValue of " + index + " = " + id);
202             if (id >= 0) return mStrings.get(id).toString();
203 
204             // May be some other type...  check and try to convert if so.
205             int t = nativeGetAttributeDataType(mParseState, index);
206             if (t == TypedValue.TYPE_NULL) {
207                 throw new IndexOutOfBoundsException(String.valueOf(index));
208             }
209 
210             int v = nativeGetAttributeData(mParseState, index);
211             return TypedValue.coerceToString(t, v);
212         }
getAttributeType(int index)213         public String getAttributeType(int index) {
214             return "CDATA";
215         }
isAttributeDefault(int index)216         public boolean isAttributeDefault(int index) {
217             return false;
218         }
nextToken()219         public int nextToken() throws XmlPullParserException,IOException {
220             return next();
221         }
getAttributeValue(String namespace, String name)222         public String getAttributeValue(String namespace, String name) {
223             int idx = nativeGetAttributeIndex(mParseState, namespace, name);
224             if (idx >= 0) {
225                 if (DEBUG) System.out.println("getAttributeName of "
226                         + namespace + ":" + name + " index = " + idx);
227                 if (DEBUG) System.out.println(
228                         "Namespace=" + getAttributeNamespace(idx)
229                         + "Name=" + getAttributeName(idx)
230                         + ", Value=" + getAttributeValue(idx));
231                 return getAttributeValue(idx);
232             }
233             return null;
234         }
next()235         public int next() throws XmlPullParserException,IOException {
236             if (!mStarted) {
237                 mStarted = true;
238                 return START_DOCUMENT;
239             }
240             if (mParseState == 0) {
241                 return END_DOCUMENT;
242             }
243             int ev = nativeNext(mParseState);
244             if (mDecNextDepth) {
245                 mDepth--;
246                 mDecNextDepth = false;
247             }
248             switch (ev) {
249             case START_TAG:
250                 mDepth++;
251                 break;
252             case END_TAG:
253                 mDecNextDepth = true;
254                 break;
255             }
256             mEventType = ev;
257             if (ev == END_DOCUMENT) {
258                 // Automatically close the parse when we reach the end of
259                 // a document, since the standard XmlPullParser interface
260                 // doesn't have such an API so most clients will leave us
261                 // dangling.
262                 close();
263             }
264             return ev;
265         }
require(int type, String namespace, String name)266         public void require(int type, String namespace, String name) throws XmlPullParserException,IOException {
267             if (type != getEventType()
268                 || (namespace != null && !namespace.equals( getNamespace () ) )
269                 || (name != null && !name.equals( getName() ) ) )
270                 throw new XmlPullParserException( "expected "+ TYPES[ type ]+getPositionDescription());
271         }
nextText()272         public String nextText() throws XmlPullParserException,IOException {
273             if(getEventType() != START_TAG) {
274                throw new XmlPullParserException(
275                  getPositionDescription()
276                  + ": parser must be on START_TAG to read next text", this, null);
277             }
278             int eventType = next();
279             if(eventType == TEXT) {
280                String result = getText();
281                eventType = next();
282                if(eventType != END_TAG) {
283                  throw new XmlPullParserException(
284                     getPositionDescription()
285                     + ": event TEXT it must be immediately followed by END_TAG", this, null);
286                 }
287                 return result;
288             } else if(eventType == END_TAG) {
289                return "";
290             } else {
291                throw new XmlPullParserException(
292                  getPositionDescription()
293                  + ": parser must be on START_TAG or TEXT to read text", this, null);
294             }
295         }
nextTag()296         public int nextTag() throws XmlPullParserException,IOException {
297             int eventType = next();
298             if(eventType == TEXT && isWhitespace()) {   // skip whitespace
299                eventType = next();
300             }
301             if (eventType != START_TAG && eventType != END_TAG) {
302                throw new XmlPullParserException(
303                    getPositionDescription()
304                    + ": expected start or end tag", this, null);
305             }
306             return eventType;
307         }
308 
getAttributeNameResource(int index)309         public int getAttributeNameResource(int index) {
310             return nativeGetAttributeResource(mParseState, index);
311         }
312 
getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue)313         public int getAttributeListValue(String namespace, String attribute,
314                 String[] options, int defaultValue) {
315             int idx = nativeGetAttributeIndex(mParseState, namespace, attribute);
316             if (idx >= 0) {
317                 return getAttributeListValue(idx, options, defaultValue);
318             }
319             return defaultValue;
320         }
getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue)321         public boolean getAttributeBooleanValue(String namespace, String attribute,
322                 boolean defaultValue) {
323             int idx = nativeGetAttributeIndex(mParseState, namespace, attribute);
324             if (idx >= 0) {
325                 return getAttributeBooleanValue(idx, defaultValue);
326             }
327             return defaultValue;
328         }
getAttributeResourceValue(String namespace, String attribute, int defaultValue)329         public int getAttributeResourceValue(String namespace, String attribute,
330                 int defaultValue) {
331             int idx = nativeGetAttributeIndex(mParseState, namespace, attribute);
332             if (idx >= 0) {
333                 return getAttributeResourceValue(idx, defaultValue);
334             }
335             return defaultValue;
336         }
getAttributeIntValue(String namespace, String attribute, int defaultValue)337         public int getAttributeIntValue(String namespace, String attribute,
338                 int defaultValue) {
339             int idx = nativeGetAttributeIndex(mParseState, namespace, attribute);
340             if (idx >= 0) {
341                 return getAttributeIntValue(idx, defaultValue);
342             }
343             return defaultValue;
344         }
getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue)345         public int getAttributeUnsignedIntValue(String namespace, String attribute,
346                                                 int defaultValue)
347         {
348             int idx = nativeGetAttributeIndex(mParseState, namespace, attribute);
349             if (idx >= 0) {
350                 return getAttributeUnsignedIntValue(idx, defaultValue);
351             }
352             return defaultValue;
353         }
getAttributeFloatValue(String namespace, String attribute, float defaultValue)354         public float getAttributeFloatValue(String namespace, String attribute,
355                 float defaultValue) {
356             int idx = nativeGetAttributeIndex(mParseState, namespace, attribute);
357             if (idx >= 0) {
358                 return getAttributeFloatValue(idx, defaultValue);
359             }
360             return defaultValue;
361         }
362 
getAttributeListValue(int idx, String[] options, int defaultValue)363         public int getAttributeListValue(int idx,
364                 String[] options, int defaultValue) {
365             int t = nativeGetAttributeDataType(mParseState, idx);
366             int v = nativeGetAttributeData(mParseState, idx);
367             if (t == TypedValue.TYPE_STRING) {
368                 return XmlUtils.convertValueToList(
369                     mStrings.get(v), options, defaultValue);
370             }
371             return v;
372         }
getAttributeBooleanValue(int idx, boolean defaultValue)373         public boolean getAttributeBooleanValue(int idx,
374                 boolean defaultValue) {
375             int t = nativeGetAttributeDataType(mParseState, idx);
376             // Note: don't attempt to convert any other types, because
377             // we want to count on appt doing the conversion for us.
378             if (t >= TypedValue.TYPE_FIRST_INT &&
379                 t <= TypedValue.TYPE_LAST_INT) {
380                 return nativeGetAttributeData(mParseState, idx) != 0;
381             }
382             return defaultValue;
383         }
getAttributeResourceValue(int idx, int defaultValue)384         public int getAttributeResourceValue(int idx, int defaultValue) {
385             int t = nativeGetAttributeDataType(mParseState, idx);
386             // Note: don't attempt to convert any other types, because
387             // we want to count on appt doing the conversion for us.
388             if (t == TypedValue.TYPE_REFERENCE) {
389                 return nativeGetAttributeData(mParseState, idx);
390             }
391             return defaultValue;
392         }
getAttributeIntValue(int idx, int defaultValue)393         public int getAttributeIntValue(int idx, int defaultValue) {
394             int t = nativeGetAttributeDataType(mParseState, idx);
395             // Note: don't attempt to convert any other types, because
396             // we want to count on appt doing the conversion for us.
397             if (t >= TypedValue.TYPE_FIRST_INT &&
398                 t <= TypedValue.TYPE_LAST_INT) {
399                 return nativeGetAttributeData(mParseState, idx);
400             }
401             return defaultValue;
402         }
getAttributeUnsignedIntValue(int idx, int defaultValue)403         public int getAttributeUnsignedIntValue(int idx, int defaultValue) {
404             int t = nativeGetAttributeDataType(mParseState, idx);
405             // Note: don't attempt to convert any other types, because
406             // we want to count on appt doing the conversion for us.
407             if (t >= TypedValue.TYPE_FIRST_INT &&
408                 t <= TypedValue.TYPE_LAST_INT) {
409                 return nativeGetAttributeData(mParseState, idx);
410             }
411             return defaultValue;
412         }
getAttributeFloatValue(int idx, float defaultValue)413         public float getAttributeFloatValue(int idx, float defaultValue) {
414             int t = nativeGetAttributeDataType(mParseState, idx);
415             // Note: don't attempt to convert any other types, because
416             // we want to count on appt doing the conversion for us.
417             if (t == TypedValue.TYPE_FLOAT) {
418                 return Float.intBitsToFloat(
419                     nativeGetAttributeData(mParseState, idx));
420             }
421             throw new RuntimeException("not a float!");
422         }
423 
getIdAttribute()424         public String getIdAttribute() {
425             int id = nativeGetIdAttribute(mParseState);
426             return id >= 0 ? mStrings.get(id).toString() : null;
427         }
getClassAttribute()428         public String getClassAttribute() {
429             int id = nativeGetClassAttribute(mParseState);
430             return id >= 0 ? mStrings.get(id).toString() : null;
431         }
432 
getIdAttributeResourceValue(int defaultValue)433         public int getIdAttributeResourceValue(int defaultValue) {
434             //todo: create and use native method
435             return getAttributeResourceValue(null, "id", defaultValue);
436         }
437 
getStyleAttribute()438         public int getStyleAttribute() {
439             return nativeGetStyleAttribute(mParseState);
440         }
441 
close()442         public void close() {
443             synchronized (mBlock) {
444                 if (mParseState != 0) {
445                     nativeDestroyParseState(mParseState);
446                     mParseState = 0;
447                     mBlock.decOpenCountLocked();
448                 }
449             }
450         }
451 
finalize()452         protected void finalize() throws Throwable {
453             close();
454         }
455 
getPooledString(int id)456         /*package*/ final CharSequence getPooledString(int id) {
457             return mStrings.get(id);
458         }
459 
460         /*package*/ int mParseState;
461         private final XmlBlock mBlock;
462         private boolean mStarted = false;
463         private boolean mDecNextDepth = false;
464         private int mDepth = 0;
465         private int mEventType = START_DOCUMENT;
466     }
467 
finalize()468     protected void finalize() throws Throwable {
469         close();
470     }
471 
472     /**
473      * Create from an existing xml block native object.  This is
474      * -extremely- dangerous -- only use it if you absolutely know what you
475      *  are doing!  The given native object must exist for the entire lifetime
476      *  of this newly creating XmlBlock.
477      */
XmlBlock(AssetManager assets, int xmlBlock)478     XmlBlock(AssetManager assets, int xmlBlock) {
479         mAssets = assets;
480         mNative = xmlBlock;
481         mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
482     }
483 
484     private final AssetManager mAssets;
485     private final int mNative;
486     private final StringBlock mStrings;
487     private boolean mOpen = true;
488     private int mOpenCount = 1;
489 
nativeCreate(byte[] data, int offset, int size)490     private static final native int nativeCreate(byte[] data,
491                                                  int offset,
492                                                  int size);
nativeGetStringBlock(int obj)493     private static final native int nativeGetStringBlock(int obj);
494 
nativeCreateParseState(int obj)495     private static final native int nativeCreateParseState(int obj);
nativeNext(int state)496     private static final native int nativeNext(int state);
nativeGetNamespace(int state)497     private static final native int nativeGetNamespace(int state);
nativeGetName(int state)498     private static final native int nativeGetName(int state);
nativeGetText(int state)499     private static final native int nativeGetText(int state);
nativeGetLineNumber(int state)500     private static final native int nativeGetLineNumber(int state);
nativeGetAttributeCount(int state)501     private static final native int nativeGetAttributeCount(int state);
nativeGetAttributeNamespace(int state, int idx)502     private static final native int nativeGetAttributeNamespace(int state, int idx);
nativeGetAttributeName(int state, int idx)503     private static final native int nativeGetAttributeName(int state, int idx);
nativeGetAttributeResource(int state, int idx)504     private static final native int nativeGetAttributeResource(int state, int idx);
nativeGetAttributeDataType(int state, int idx)505     private static final native int nativeGetAttributeDataType(int state, int idx);
nativeGetAttributeData(int state, int idx)506     private static final native int nativeGetAttributeData(int state, int idx);
nativeGetAttributeStringValue(int state, int idx)507     private static final native int nativeGetAttributeStringValue(int state, int idx);
nativeGetIdAttribute(int state)508     private static final native int nativeGetIdAttribute(int state);
nativeGetClassAttribute(int state)509     private static final native int nativeGetClassAttribute(int state);
nativeGetStyleAttribute(int state)510     private static final native int nativeGetStyleAttribute(int state);
nativeGetAttributeIndex(int state, String namespace, String name)511     private static final native int nativeGetAttributeIndex(int state, String namespace, String name);
nativeDestroyParseState(int state)512     private static final native void nativeDestroyParseState(int state);
513 
nativeDestroy(int obj)514     private static final native void nativeDestroy(int obj);
515 }
516