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