ParserFactory.java revision 4bf28b6af45f76a33b466ad8157aa1844716cbcb
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 204bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Guptaimport com.android.annotations.NonNull; 214bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Guptaimport com.android.annotations.Nullable; 224bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback; 234bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta 24ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport org.xmlpull.v1.XmlPullParser; 25ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport org.xmlpull.v1.XmlPullParserException; 26ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 27ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.BufferedInputStream; 28ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.ByteArrayInputStream; 29ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.File; 30ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.FileInputStream; 31ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.FileNotFoundException; 32ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.IOException; 33ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskiimport java.io.InputStream; 34ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 35ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski/** 36ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * A factory for {@link XmlPullParser}. 37ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski * 38ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski */ 39ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinskipublic class ParserFactory { 40ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 414bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta public final static boolean LOG_PARSER = false; 424bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta 43ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski private final static String ENCODING = "UTF-8"; //$NON-NLS-1$ 44ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 454bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta // Used to get a new XmlPullParser from the client. 464bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @Nullable 474bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta private static LayoutlibCallback sLayoutlibCallback; 48ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 494bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta public static void setLayoutlibCallback(@Nullable LayoutlibCallback callback) { 504bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta sLayoutlibCallback = callback; 514bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta } 524bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta 534bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @NonNull 544bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta public static XmlPullParser create(@NonNull File f) 55ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski throws XmlPullParserException, FileNotFoundException { 56ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski InputStream stream = new FileInputStream(f); 57ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return create(stream, f.getName(), f.length()); 58ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 59ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 604bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @NonNull 614bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name) 62ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski throws XmlPullParserException { 63ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return create(stream, name, -1); 64ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 65ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 664bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @NonNull 674bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name, 684bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta long size) throws XmlPullParserException { 694bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta XmlPullParser parser = instantiateParser(name); 70ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 71ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski stream = readAndClose(stream, name, size); 72ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 73ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski parser.setInput(stream, ENCODING); 74ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return parser; 75ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 76ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 774bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @NonNull 784bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta public static XmlPullParser instantiateParser(@Nullable String name) 794bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta throws XmlPullParserException { 804bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta if (sLayoutlibCallback == null) { 814bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta throw new XmlPullParserException("ParserFactory not initialized."); 82ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 834bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta XmlPullParser parser = sLayoutlibCallback.createParser(name); 84ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 85ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return parser; 86ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 87ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 884bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @NonNull 894bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name, 904bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta long size) throws XmlPullParserException { 91ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // just a sanity check. It's doubtful we'll have such big files! 92ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (size > Integer.MAX_VALUE) { 93ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski throw new XmlPullParserException("File " + name + " is too big to be parsed"); 94ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 95ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski int intSize = (int) size; 96ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 97ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // create a buffered reader to facilitate reading. 98ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski BufferedInputStream bufferedStream = new BufferedInputStream(stream); 99ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski try { 100ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski int avail; 101ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (intSize != -1) { 102ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski avail = intSize; 103ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } else { 104ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // get the size to read. 105ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski avail = bufferedStream.available(); 106ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 107ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 108ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // create the initial buffer and read it. 109ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski byte[] buffer = new byte[avail]; 110ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski int read = stream.read(buffer); 111ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 112ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // this is the easy case. 113ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (read == intSize) { 114ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return new ByteArrayInputStream(buffer); 115ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 116ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 117ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // check if there is more to read (read() does not necessarily read all that 118ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // available() returned!) 119ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski while ((avail = bufferedStream.available()) > 0) { 120ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski if (read + avail > buffer.length) { 121ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // just allocate what is needed. We're mostly reading small files 122ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // so it shouldn't be too problematic. 123ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski byte[] moreBuffer = new byte[read + avail]; 124ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski System.arraycopy(buffer, 0, moreBuffer, 0, read); 125ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski buffer = moreBuffer; 126ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 127ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 128ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski read += stream.read(buffer, read, avail); 129ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 130ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 131ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski // return a new stream encapsulating this buffer. 132ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski return new ByteArrayInputStream(buffer); 133ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski 134ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } catch (IOException e) { 135ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski throw new XmlPullParserException("Failed to read " + name, null, e); 136ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } finally { 137ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski try { 138ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski bufferedStream.close(); 1394bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta } catch (IOException ignored) { 140ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 141ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 142ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski } 143ab775ecdd189b32e35b0d3f4a821502f88b03a4bAdam Lesinski} 144