• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     // Used to get a new XmlPullParser from the client.
43     @Nullable
44     private static com.android.ide.common.rendering.api.ParserFactory sParserFactory;
45 
setParserFactory( @ullable com.android.ide.common.rendering.api.ParserFactory parserFactory)46     public static void setParserFactory(
47             @Nullable com.android.ide.common.rendering.api.ParserFactory parserFactory) {
48         sParserFactory = parserFactory;
49     }
50 
51     @NonNull
create(@onNull File f)52     public static XmlPullParser create(@NonNull File f)
53             throws XmlPullParserException, FileNotFoundException {
54         return create(f, false);
55     }
56 
create(@onNull File f, boolean isLayout)57     public static XmlPullParser create(@NonNull File f, boolean isLayout)
58       throws XmlPullParserException, FileNotFoundException {
59         InputStream stream = new FileInputStream(f);
60         return create(stream, f.getName(), f.length(), isLayout);
61     }
62     @NonNull
create(@onNull InputStream stream, @Nullable String name)63     public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
64         throws XmlPullParserException {
65         return create(stream, name, -1, false);
66     }
67 
68     @NonNull
create(@onNull InputStream stream, @Nullable String name, long size, boolean isLayout)69     private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
70             long size, boolean isLayout) throws XmlPullParserException {
71         XmlPullParser parser = instantiateParser(name);
72 
73         stream = readAndClose(stream, name, size);
74 
75         parser.setInput(stream, null);
76         if (isLayout) {
77             try {
78                 return new LayoutParserWrapper(parser).peekTillLayoutStart();
79             } catch (IOException e) {
80                 throw new XmlPullParserException(null, parser, e);
81             }
82         }
83         return parser;
84     }
85 
86     @NonNull
instantiateParser(@ullable String name)87     public static XmlPullParser instantiateParser(@Nullable String name)
88             throws XmlPullParserException {
89         if (sParserFactory == null) {
90             throw new XmlPullParserException("ParserFactory not initialized.");
91         }
92         XmlPullParser parser = sParserFactory.createParser(name);
93         parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
94         return parser;
95     }
96 
97     @NonNull
readAndClose(@onNull InputStream stream, @Nullable String name, long size)98     private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name,
99             long size) throws XmlPullParserException {
100         // just a sanity check. It's doubtful we'll have such big files!
101         if (size > Integer.MAX_VALUE) {
102             throw new XmlPullParserException("File " + name + " is too big to be parsed");
103         }
104         int intSize = (int) size;
105 
106         // create a buffered reader to facilitate reading.
107         BufferedInputStream bufferedStream = new BufferedInputStream(stream);
108         try {
109             int avail;
110             if (intSize != -1) {
111                 avail = intSize;
112             } else {
113                 // get the size to read.
114                 avail = bufferedStream.available();
115             }
116 
117             // create the initial buffer and read it.
118             byte[] buffer = new byte[avail];
119             int read = stream.read(buffer);
120 
121             // this is the easy case.
122             if (read == intSize) {
123                 return new ByteArrayInputStream(buffer);
124             }
125 
126             // check if there is more to read (read() does not necessarily read all that
127             // available() returned!)
128             while ((avail = bufferedStream.available()) > 0) {
129                 if (read + avail > buffer.length) {
130                     // just allocate what is needed. We're mostly reading small files
131                     // so it shouldn't be too problematic.
132                     byte[] moreBuffer = new byte[read + avail];
133                     System.arraycopy(buffer, 0, moreBuffer, 0, read);
134                     buffer = moreBuffer;
135                 }
136 
137                 read += stream.read(buffer, read, avail);
138             }
139 
140             // return a new stream encapsulating this buffer.
141             return new ByteArrayInputStream(buffer);
142 
143         } catch (IOException e) {
144             throw new XmlPullParserException("Failed to read " + name, null, e);
145         } finally {
146             try {
147                 bufferedStream.close();
148             } catch (IOException ignored) {
149             }
150         }
151     }
152 }
153