104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet/* 204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * Copyright (C) 2011 The Android Open Source Project 304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * 404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License"); 504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * you may not use this file except in compliance with the License. 604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * You may obtain a copy of the License at 704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * 804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * http://www.apache.org/licenses/LICENSE-2.0 904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * 1004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software 1104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS, 1204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * See the License for the specific language governing permissions and 1404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * limitations under the License. 1504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet */ 1604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 1704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetpackage com.android.layoutlib.bridge.impl; 1804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 1904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 2004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport org.kxml2.io.KXmlParser; 2104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport org.xmlpull.v1.XmlPullParser; 2204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport org.xmlpull.v1.XmlPullParserException; 2304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 24c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohetimport java.io.BufferedInputStream; 25c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohetimport java.io.ByteArrayInputStream; 2604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.File; 2704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.FileInputStream; 2804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.FileNotFoundException; 29c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohetimport java.io.IOException; 3004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.InputStream; 3104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 3204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet/** 3304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * A factory for {@link XmlPullParser}. 3404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * 3504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet */ 3604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetpublic class ParserFactory { 3704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 3804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet private final static String ENCODING = "UTF-8"; //$NON-NLS-1$ 3904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 4004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet public final static boolean LOG_PARSER = false; 4104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 4204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet public static XmlPullParser create(File f) 4304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet throws XmlPullParserException, FileNotFoundException { 44c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet InputStream stream = new FileInputStream(f); 45c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet return create(stream, f.getName(), f.length()); 4604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 4704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 4804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet public static XmlPullParser create(InputStream stream, String name) 49c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet throws XmlPullParserException { 50c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet return create(stream, name, -1); 51c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 52c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 53c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet private static XmlPullParser create(InputStream stream, String name, long size) 5404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet throws XmlPullParserException { 5504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet KXmlParser parser = instantiateParser(name); 56c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 57c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet stream = readAndClose(stream, name, size); 58c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 5904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet parser.setInput(stream, ENCODING); 6004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet return parser; 6104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 6204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 6304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet private static KXmlParser instantiateParser(String name) throws XmlPullParserException { 6404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet KXmlParser parser; 6504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet if (name != null) { 6604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet parser = new CustomParser(name); 6704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } else { 6804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet parser = new KXmlParser(); 6904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 7004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 7104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet return parser; 7204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 7304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 74c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet private static InputStream readAndClose(InputStream stream, String name, long size) 75c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet throws XmlPullParserException { 76c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // just a sanity check. It's doubtful we'll have such big files! 77c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet if (size > Integer.MAX_VALUE) { 78c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet throw new XmlPullParserException("File " + name + " is too big to be parsed"); 79c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 80c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet int intSize = (int) size; 81c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 82c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // create a buffered reader to facilitate reading. 83c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet BufferedInputStream bufferedStream = new BufferedInputStream(stream); 84c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet try { 85c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet int avail; 86c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet if (intSize != -1) { 87c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet avail = intSize; 88c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } else { 89c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // get the size to read. 90c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet avail = bufferedStream.available(); 91c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 92c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 93c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // create the initial buffer and read it. 94c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet byte[] buffer = new byte[avail]; 95c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet int read = stream.read(buffer); 96c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 97c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // this is the easy case. 98c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet if (read == intSize) { 99c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet return new ByteArrayInputStream(buffer); 100c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 101c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 102c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // check if there is more to read (read() does not necessarily read all that 103c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // available() returned!) 104c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet while ((avail = bufferedStream.available()) > 0) { 105c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet if (read + avail > buffer.length) { 106c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // just allocate what is needed. We're mostly reading small files 107c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // so it shouldn't be too problematic. 108c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet byte[] moreBuffer = new byte[read + avail]; 109c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet System.arraycopy(buffer, 0, moreBuffer, 0, read); 110c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet buffer = moreBuffer; 111c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 112c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 113c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet read += stream.read(buffer, read, avail); 114c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 115c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 116c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet // return a new stream encapsulating this buffer. 117c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet return new ByteArrayInputStream(buffer); 118c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 119c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } catch (IOException e) { 120c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet throw new XmlPullParserException("Failed to read " + name, null, e); 121c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } finally { 122c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet try { 123c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet bufferedStream.close(); 124c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } catch (IOException e) { 125c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 126c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 127c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet } 128c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet 12904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet private static class CustomParser extends KXmlParser { 13004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet private final String mName; 13104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 13204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet CustomParser(String name) { 13304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet super(); 13404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet mName = name; 13504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 13604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet 13704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet @Override 13804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet public String toString() { 13904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet return mName; 14004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 14104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet } 14204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet} 143