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