1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2011 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.layoutlib.bridge.impl; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.kxml2.io.KXmlParser; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.xmlpull.v1.XmlPullParser; 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException; 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.BufferedInputStream; 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.ByteArrayInputStream; 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.File; 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.FileInputStream; 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.FileNotFoundException; 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.IOException; 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.InputStream; 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * A factory for {@link XmlPullParser}. 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic class ParserFactory { 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final static String ENCODING = "UTF-8"; //$NON-NLS-1$ 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public final static boolean LOG_PARSER = false; 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static XmlPullParser create(File f) 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throws XmlPullParserException, FileNotFoundException { 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski InputStream stream = new FileInputStream(f); 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return create(stream, f.getName(), f.length()); 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public static XmlPullParser create(InputStream stream, String name) 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throws XmlPullParserException { 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return create(stream, name, -1); 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static XmlPullParser create(InputStream stream, String name, long size) 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throws XmlPullParserException { 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski KXmlParser parser = instantiateParser(name); 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski stream = readAndClose(stream, name, size); 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski parser.setInput(stream, ENCODING); 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return parser; 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static KXmlParser instantiateParser(String name) throws XmlPullParserException { 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski KXmlParser parser; 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (name != null) { 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski parser = new CustomParser(name); 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski parser = new KXmlParser(); 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return parser; 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static InputStream readAndClose(InputStream stream, String name, long size) 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throws XmlPullParserException { 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // just a sanity check. It's doubtful we'll have such big files! 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (size > Integer.MAX_VALUE) { 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throw new XmlPullParserException("File " + name + " is too big to be parsed"); 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int intSize = (int) size; 81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // create a buffered reader to facilitate reading. 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski BufferedInputStream bufferedStream = new BufferedInputStream(stream); 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int avail; 86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (intSize != -1) { 87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski avail = intSize; 88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } else { 89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // get the size to read. 90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski avail = bufferedStream.available(); 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // create the initial buffer and read it. 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski byte[] buffer = new byte[avail]; 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int read = stream.read(buffer); 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // this is the easy case. 98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (read == intSize) { 99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return new ByteArrayInputStream(buffer); 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // check if there is more to read (read() does not necessarily read all that 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // available() returned!) 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski while ((avail = bufferedStream.available()) > 0) { 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (read + avail > buffer.length) { 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // just allocate what is needed. We're mostly reading small files 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // so it shouldn't be too problematic. 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski byte[] moreBuffer = new byte[read + avail]; 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski System.arraycopy(buffer, 0, moreBuffer, 0, read); 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski buffer = moreBuffer; 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski read += stream.read(buffer, read, avail); 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // return a new stream encapsulating this buffer. 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return new ByteArrayInputStream(buffer); 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (IOException e) { 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski throw new XmlPullParserException("Failed to read " + name, null, e); 121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } finally { 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski try { 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski bufferedStream.close(); 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } catch (IOException e) { 125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static class CustomParser extends KXmlParser { 130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final String mName; 131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski CustomParser(String name) { 133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski super(); 134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mName = name; 135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public String toString() { 139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return mName; 140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 143