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