ParserFactory.java revision ab775ecdd189b32e35b0d3f4a821502f88b03a4b
1ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski/*
2ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Copyright (C) 2011 The Android Open Source Project
3ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski *
4ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * you may not use this file except in compliance with the License.
6ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * You may obtain a copy of the License at
7ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski *
8ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski *
10ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * Unless required by applicable law or agreed to in writing, software
11ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * See the License for the specific language governing permissions and
14ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * limitations under the License.
15ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski */
16ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
17ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskipackage com.android.layoutlib.bridge.impl;
18ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
19ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
20ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport org.kxml2.io.KXmlParser;
21ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport org.xmlpull.v1.XmlPullParser;
22ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport org.xmlpull.v1.XmlPullParserException;
23ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
24ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.BufferedInputStream;
25ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.ByteArrayInputStream;
26ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.File;
27ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.FileInputStream;
28ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.FileNotFoundException;
29ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.IOException;
30ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.InputStream;
31ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
32ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski/**
33ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * A factory for {@link XmlPullParser}.
34ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski *
35ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski */
36ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskipublic class ParserFactory {
37ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
38ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    private final static String ENCODING = "UTF-8"; //$NON-NLS-1$
39ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
40ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    public final static boolean LOG_PARSER = false;
41ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
42ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    public static XmlPullParser create(File f)
43ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            throws XmlPullParserException, FileNotFoundException {
44ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        InputStream stream = new FileInputStream(f);
45ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        return create(stream, f.getName(), f.length());
46ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    }
47ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
48ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    public static XmlPullParser create(InputStream stream, String name)
49ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        throws XmlPullParserException {
50ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        return create(stream, name, -1);
51ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    }
52ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
53ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    private static XmlPullParser create(InputStream stream, String name, long size)
54ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            throws XmlPullParserException {
55ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        KXmlParser parser = instantiateParser(name);
56ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
57ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        stream = readAndClose(stream, name, size);
58ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
59ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        parser.setInput(stream, ENCODING);
60ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        return parser;
61ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    }
62ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
63ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    private static KXmlParser instantiateParser(String name) throws XmlPullParserException {
64ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        KXmlParser parser;
65ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        if (name != null) {
66ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            parser = new CustomParser(name);
67ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        } else {
68ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            parser = new KXmlParser();
69ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        }
70ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
71ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        return parser;
72ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    }
73ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
74ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    private static InputStream readAndClose(InputStream stream, String name, long size)
75ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            throws XmlPullParserException {
76ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        // just a sanity check. It's doubtful we'll have such big files!
77ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        if (size > Integer.MAX_VALUE) {
78ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            throw new XmlPullParserException("File " + name + " is too big to be parsed");
79ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        }
80ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        int intSize = (int) size;
81ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
82ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        // create a buffered reader to facilitate reading.
83ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        BufferedInputStream bufferedStream = new BufferedInputStream(stream);
84ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        try {
85ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            int avail;
86ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            if (intSize != -1) {
87ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                avail = intSize;
88ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            } else {
89ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                // get the size to read.
90ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                avail = bufferedStream.available();
91ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            }
92ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
93ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            // create the initial buffer and read it.
94ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            byte[] buffer = new byte[avail];
95ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            int read = stream.read(buffer);
96ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
97ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            // this is the easy case.
98ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            if (read == intSize) {
99ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                return new ByteArrayInputStream(buffer);
100ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            }
101ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
102ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            // check if there is more to read (read() does not necessarily read all that
103ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            // available() returned!)
104ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            while ((avail = bufferedStream.available()) > 0) {
105ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                if (read + avail > buffer.length) {
106ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                    // just allocate what is needed. We're mostly reading small files
107ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                    // so it shouldn't be too problematic.
108ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                    byte[] moreBuffer = new byte[read + avail];
109ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                    System.arraycopy(buffer, 0, moreBuffer, 0, read);
110ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                    buffer = moreBuffer;
111ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                }
112ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
113ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                read += stream.read(buffer, read, avail);
114ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            }
115ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
116ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            // return a new stream encapsulating this buffer.
117ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            return new ByteArrayInputStream(buffer);
118ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
119ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        } catch (IOException e) {
120ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            throw new XmlPullParserException("Failed to read " + name, null, e);
121ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        } finally {
122ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            try {
123ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski                bufferedStream.close();
124ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            } catch (IOException e) {
125ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            }
126ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        }
127ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    }
128ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
129ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    private static class CustomParser extends KXmlParser {
130ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        private final String mName;
131ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
132ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        CustomParser(String name) {
133ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            super();
134ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            mName = name;
135ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        }
136ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski
137ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        @Override
138ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        public String toString() {
139ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski            return mName;
140ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski        }
141ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski    }
142ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski}
143