blob: 38b7aa50086928ace0d1fe1861d0d0cfc4dcd9f0 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
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
19import com.android.ide.common.rendering.api.XmlParserFactory;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
24import android.annotation.NonNull;
25import android.annotation.Nullable;
26
27import java.io.BufferedInputStream;
28import java.io.ByteArrayInputStream;
29import java.io.IOException;
30import java.io.InputStream;
31
32/**
33 * A factory for {@link XmlPullParser}.
34 */
35public class ParserFactory {
36 public final static boolean LOG_PARSER = false;
37
38 // Used to get a new XmlPullParser from the client.
39 @Nullable
40 private static XmlParserFactory sParserFactory;
41
42 public static void setParserFactory(@Nullable XmlParserFactory parserFactory) {
43 sParserFactory = parserFactory;
44 }
45
46 @Nullable
47 public static XmlPullParser create(@NonNull String filePath)
48 throws XmlPullParserException {
49 return create(filePath, false);
50 }
51
52 @Nullable
53 public static XmlPullParser create(@NonNull String filePath, boolean isLayout)
54 throws XmlPullParserException {
55 XmlPullParser parser = sParserFactory.createXmlParserForFile(filePath);
56 if (parser != null && isLayout) {
57 try {
58 return new LayoutParserWrapper(parser).peekTillLayoutStart();
59 } catch (IOException e) {
60 throw new XmlPullParserException(null, parser, e);
61 }
62 }
63 return parser;
64 }
65
66 @NonNull
67 public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
68 throws XmlPullParserException {
69 XmlPullParser parser = create();
70
71 stream = readAndClose(stream, name);
72
73 parser.setInput(stream, null);
74 return parser;
75 }
76
77 @NonNull
78 public static XmlPullParser create() throws XmlPullParserException {
79 if (sParserFactory == null) {
80 throw new XmlPullParserException("ParserFactory not initialized.");
81 }
82 XmlPullParser parser = sParserFactory.createXmlParser();
83 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
84 return parser;
85 }
86
87 @NonNull
88 private static InputStream readAndClose(@NonNull InputStream stream, @Nullable String name)
89 throws XmlPullParserException {
90 // Create a buffered stream to facilitate reading.
91 try (BufferedInputStream bufferedStream = new BufferedInputStream(stream)) {
92 int avail = bufferedStream.available();
93
94 // Create the initial buffer and read it.
95 byte[] buffer = new byte[avail];
96 int read = stream.read(buffer);
97
98 // Check if there is more to read (read() does not necessarily read all that
99 // available() returned!)
100 while ((avail = bufferedStream.available()) > 0) {
101 if (read + avail > buffer.length) {
102 // just allocate what is needed. We're mostly reading small files
103 // so it shouldn't be too problematic.
104 byte[] moreBuffer = new byte[read + avail];
105 System.arraycopy(buffer, 0, moreBuffer, 0, read);
106 buffer = moreBuffer;
107 }
108
109 read += stream.read(buffer, read, avail);
110 }
111
112 // Return a new stream encapsulating this buffer.
113 return new ByteArrayInputStream(buffer);
114 } catch (IOException e) {
115 throw new XmlPullParserException("Failed to read " + name, null, e);
116 }
117 }
118}