1/*
2 * Copyright (C) 2008 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
17package com.android.layoutlib.bridge;
18
19import com.android.layoutlib.api.IXmlPullParser;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
24import android.content.res.XmlResourceParser;
25import android.util.AttributeSet;
26import android.util.XmlPullAttributes;
27
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.Reader;
31
32/**
33 * {@link BridgeXmlBlockParser} reimplements most of android.xml.XmlBlock.Parser.
34 * It delegates to both an instance of {@link XmlPullParser} and an instance of
35 * {@link XmlPullAttributes} (for the {@link AttributeSet} part).
36 */
37public class BridgeXmlBlockParser implements XmlResourceParser {
38
39    private XmlPullParser mParser;
40    private XmlPullAttributes mAttrib;
41
42    private boolean mStarted = false;
43    private boolean mDecNextDepth = false;
44    private int mDepth = 0;
45    private int mEventType = START_DOCUMENT;
46    private final boolean mPlatformFile;
47
48    /**
49     * Builds a {@link BridgeXmlBlockParser}.
50     * @param parser The XmlPullParser to get the content from.
51     * @param context the Context.
52     * @param platformFile Indicates whether the the file is a platform file or not.
53     */
54    public BridgeXmlBlockParser(XmlPullParser parser, BridgeContext context, boolean platformFile) {
55        mParser = parser;
56        mPlatformFile = platformFile;
57        mAttrib = new BridgeXmlPullAttributes(parser, context, mPlatformFile);
58    }
59
60    public boolean isPlatformFile() {
61        return mPlatformFile;
62    }
63
64    public Object getViewKey() {
65        if (mParser instanceof IXmlPullParser) {
66            return ((IXmlPullParser)mParser).getViewKey();
67        }
68
69        return null;
70    }
71
72
73    // ------- XmlResourceParser implementation
74
75    public void setFeature(String name, boolean state)
76            throws XmlPullParserException {
77        if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
78            return;
79        }
80        if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) {
81            return;
82        }
83        throw new XmlPullParserException("Unsupported feature: " + name);
84    }
85
86    public boolean getFeature(String name) {
87        if (FEATURE_PROCESS_NAMESPACES.equals(name)) {
88            return true;
89        }
90        if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
91            return true;
92        }
93        return false;
94    }
95
96    public void setProperty(String name, Object value) throws XmlPullParserException {
97        throw new XmlPullParserException("setProperty() not supported");
98    }
99
100    public Object getProperty(String name) {
101        return null;
102    }
103
104    public void setInput(Reader in) throws XmlPullParserException {
105        mParser.setInput(in);
106    }
107
108    public void setInput(InputStream inputStream, String inputEncoding)
109            throws XmlPullParserException {
110        mParser.setInput(inputStream, inputEncoding);
111    }
112
113    public void defineEntityReplacementText(String entityName,
114            String replacementText) throws XmlPullParserException {
115        throw new XmlPullParserException(
116                "defineEntityReplacementText() not supported");
117    }
118
119    public String getNamespacePrefix(int pos) throws XmlPullParserException {
120        throw new XmlPullParserException("getNamespacePrefix() not supported");
121    }
122
123    public String getInputEncoding() {
124        return null;
125    }
126
127    public String getNamespace(String prefix) {
128        throw new RuntimeException("getNamespace() not supported");
129    }
130
131    public int getNamespaceCount(int depth) throws XmlPullParserException {
132        throw new XmlPullParserException("getNamespaceCount() not supported");
133    }
134
135    public String getPositionDescription() {
136        return "Binary XML file line #" + getLineNumber();
137    }
138
139    public String getNamespaceUri(int pos) throws XmlPullParserException {
140        throw new XmlPullParserException("getNamespaceUri() not supported");
141    }
142
143    public int getColumnNumber() {
144        return -1;
145    }
146
147    public int getDepth() {
148        return mDepth;
149    }
150
151    public String getText() {
152        return mParser.getText();
153    }
154
155    public int getLineNumber() {
156        return mParser.getLineNumber();
157    }
158
159    public int getEventType() {
160        return mEventType;
161    }
162
163    public boolean isWhitespace() throws XmlPullParserException {
164        // Original comment: whitespace was stripped by aapt.
165        return mParser.isWhitespace();
166    }
167
168    public String getPrefix() {
169        throw new RuntimeException("getPrefix not supported");
170    }
171
172    public char[] getTextCharacters(int[] holderForStartAndLength) {
173        String txt = getText();
174        char[] chars = null;
175        if (txt != null) {
176            holderForStartAndLength[0] = 0;
177            holderForStartAndLength[1] = txt.length();
178            chars = new char[txt.length()];
179            txt.getChars(0, txt.length(), chars, 0);
180        }
181        return chars;
182    }
183
184    public String getNamespace() {
185        return mParser.getNamespace();
186    }
187
188    public String getName() {
189        return mParser.getName();
190    }
191
192    public String getAttributeNamespace(int index) {
193        return mParser.getAttributeNamespace(index);
194    }
195
196    public String getAttributeName(int index) {
197        return mParser.getAttributeName(index);
198    }
199
200    public String getAttributePrefix(int index) {
201        throw new RuntimeException("getAttributePrefix not supported");
202    }
203
204    public boolean isEmptyElementTag() {
205        // XXX Need to detect this.
206        return false;
207    }
208
209    public int getAttributeCount() {
210        return mParser.getAttributeCount();
211    }
212
213    public String getAttributeValue(int index) {
214        return mParser.getAttributeValue(index);
215    }
216
217    public String getAttributeType(int index) {
218        return "CDATA";
219    }
220
221    public boolean isAttributeDefault(int index) {
222        return false;
223    }
224
225    public int nextToken() throws XmlPullParserException, IOException {
226        return next();
227    }
228
229    public String getAttributeValue(String namespace, String name) {
230        return mParser.getAttributeValue(namespace, name);
231    }
232
233    public int next() throws XmlPullParserException, IOException {
234        if (!mStarted) {
235            mStarted = true;
236            return START_DOCUMENT;
237        }
238        int ev = mParser.next();
239        if (mDecNextDepth) {
240            mDepth--;
241            mDecNextDepth = false;
242        }
243        switch (ev) {
244        case START_TAG:
245            mDepth++;
246            break;
247        case END_TAG:
248            mDecNextDepth = true;
249            break;
250        }
251        mEventType = ev;
252        return ev;
253    }
254
255    public void require(int type, String namespace, String name)
256            throws XmlPullParserException {
257        if (type != getEventType()
258                || (namespace != null && !namespace.equals(getNamespace()))
259                || (name != null && !name.equals(getName())))
260            throw new XmlPullParserException("expected " + TYPES[type]
261                    + getPositionDescription());
262    }
263
264    public String nextText() throws XmlPullParserException, IOException {
265        if (getEventType() != START_TAG) {
266            throw new XmlPullParserException(getPositionDescription()
267                    + ": parser must be on START_TAG to read next text", this,
268                    null);
269        }
270        int eventType = next();
271        if (eventType == TEXT) {
272            String result = getText();
273            eventType = next();
274            if (eventType != END_TAG) {
275                throw new XmlPullParserException(
276                        getPositionDescription()
277                                + ": event TEXT it must be immediately followed by END_TAG",
278                        this, null);
279            }
280            return result;
281        } else if (eventType == END_TAG) {
282            return "";
283        } else {
284            throw new XmlPullParserException(getPositionDescription()
285                    + ": parser must be on START_TAG or TEXT to read text",
286                    this, null);
287        }
288    }
289
290    public int nextTag() throws XmlPullParserException, IOException {
291        int eventType = next();
292        if (eventType == TEXT && isWhitespace()) { // skip whitespace
293            eventType = next();
294        }
295        if (eventType != START_TAG && eventType != END_TAG) {
296            throw new XmlPullParserException(getPositionDescription()
297                    + ": expected start or end tag", this, null);
298        }
299        return eventType;
300    }
301
302    // AttributeSet implementation
303
304
305    public void close() {
306        // pass
307    }
308
309    public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
310        return mAttrib.getAttributeBooleanValue(index, defaultValue);
311    }
312
313    public boolean getAttributeBooleanValue(String namespace, String attribute,
314            boolean defaultValue) {
315        return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue);
316    }
317
318    public float getAttributeFloatValue(int index, float defaultValue) {
319        return mAttrib.getAttributeFloatValue(index, defaultValue);
320    }
321
322    public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
323        return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue);
324    }
325
326    public int getAttributeIntValue(int index, int defaultValue) {
327        return mAttrib.getAttributeIntValue(index, defaultValue);
328    }
329
330    public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
331        return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue);
332    }
333
334    public int getAttributeListValue(int index, String[] options, int defaultValue) {
335        return mAttrib.getAttributeListValue(index, options, defaultValue);
336    }
337
338    public int getAttributeListValue(String namespace, String attribute,
339            String[] options, int defaultValue) {
340        return mAttrib.getAttributeListValue(namespace, attribute, options, defaultValue);
341    }
342
343    public int getAttributeNameResource(int index) {
344        return mAttrib.getAttributeNameResource(index);
345    }
346
347    public int getAttributeResourceValue(int index, int defaultValue) {
348        return mAttrib.getAttributeResourceValue(index, defaultValue);
349    }
350
351    public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
352        return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue);
353    }
354
355    public int getAttributeUnsignedIntValue(int index, int defaultValue) {
356        return mAttrib.getAttributeUnsignedIntValue(index, defaultValue);
357    }
358
359    public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
360        return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue);
361    }
362
363    public String getClassAttribute() {
364        return mAttrib.getClassAttribute();
365    }
366
367    public String getIdAttribute() {
368        return mAttrib.getIdAttribute();
369    }
370
371    public int getIdAttributeResourceValue(int defaultValue) {
372        return mAttrib.getIdAttributeResourceValue(defaultValue);
373    }
374
375    public int getStyleAttribute() {
376        return mAttrib.getStyleAttribute();
377    }
378}
379