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 17 package com.android.layoutlib.bridge.impl; 18 19 20 import org.xmlpull.v1.XmlPullParser; 21 import org.xmlpull.v1.XmlPullParserException; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 26 import java.io.BufferedInputStream; 27 import java.io.ByteArrayInputStream; 28 import java.io.File; 29 import java.io.FileInputStream; 30 import java.io.FileNotFoundException; 31 import java.io.IOException; 32 import java.io.InputStream; 33 34 /** 35 * A factory for {@link XmlPullParser}. 36 * 37 */ 38 public class ParserFactory { 39 40 public final static boolean LOG_PARSER = false; 41 42 private final static String ENCODING = "UTF-8"; //$NON-NLS-1$ 43 44 // Used to get a new XmlPullParser from the client. 45 @Nullable 46 private static com.android.ide.common.rendering.api.ParserFactory sParserFactory; 47 setParserFactory( @ullable com.android.ide.common.rendering.api.ParserFactory parserFactory)48 public static void setParserFactory( 49 @Nullable com.android.ide.common.rendering.api.ParserFactory parserFactory) { 50 sParserFactory = parserFactory; 51 } 52 53 @NonNull create(@onNull File f)54 public static XmlPullParser create(@NonNull File f) 55 throws XmlPullParserException, FileNotFoundException { 56 InputStream stream = new FileInputStream(f); 57 return create(stream, f.getName(), f.length()); 58 } 59 60 @NonNull create(@onNull InputStream stream, @Nullable String name)61 public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name) 62 throws XmlPullParserException { 63 return create(stream, name, -1); 64 } 65 66 @NonNull create(@onNull InputStream stream, @Nullable String name, long size)67 private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name, 68 long size) throws XmlPullParserException { 69 XmlPullParser parser = instantiateParser(name); 70 71 stream = readAndClose(stream, name, size); 72 73 parser.setInput(stream, ENCODING); 74 return parser; 75 } 76 77 @NonNull instantiateParser(@ullable String name)78 public static XmlPullParser instantiateParser(@Nullable String name) 79 throws XmlPullParserException { 80 if (sParserFactory == null) { 81 throw new XmlPullParserException("ParserFactory not initialized."); 82 } 83 XmlPullParser parser = sParserFactory.createParser(name); 84 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 85 return parser; 86 } 87 88 @NonNull readAndClose(@onNull InputStream stream, @Nullable String name, long size)89 private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name, 90 long size) throws XmlPullParserException { 91 // just a sanity check. It's doubtful we'll have such big files! 92 if (size > Integer.MAX_VALUE) { 93 throw new XmlPullParserException("File " + name + " is too big to be parsed"); 94 } 95 int intSize = (int) size; 96 97 // create a buffered reader to facilitate reading. 98 BufferedInputStream bufferedStream = new BufferedInputStream(stream); 99 try { 100 int avail; 101 if (intSize != -1) { 102 avail = intSize; 103 } else { 104 // get the size to read. 105 avail = bufferedStream.available(); 106 } 107 108 // create the initial buffer and read it. 109 byte[] buffer = new byte[avail]; 110 int read = stream.read(buffer); 111 112 // this is the easy case. 113 if (read == intSize) { 114 return new ByteArrayInputStream(buffer); 115 } 116 117 // check if there is more to read (read() does not necessarily read all that 118 // available() returned!) 119 while ((avail = bufferedStream.available()) > 0) { 120 if (read + avail > buffer.length) { 121 // just allocate what is needed. We're mostly reading small files 122 // so it shouldn't be too problematic. 123 byte[] moreBuffer = new byte[read + avail]; 124 System.arraycopy(buffer, 0, moreBuffer, 0, read); 125 buffer = moreBuffer; 126 } 127 128 read += stream.read(buffer, read, avail); 129 } 130 131 // return a new stream encapsulating this buffer. 132 return new ByteArrayInputStream(buffer); 133 134 } catch (IOException e) { 135 throw new XmlPullParserException("Failed to read " + name, null, e); 136 } finally { 137 try { 138 bufferedStream.close(); 139 } catch (IOException ignored) { 140 } 141 } 142 } 143 } 144