• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.internal.util;
18 
19 import org.xmlpull.v1.XmlSerializer;
20 
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.io.OutputStreamWriter;
24 import java.io.UnsupportedEncodingException;
25 import java.io.Writer;
26 import java.nio.ByteBuffer;
27 import java.nio.CharBuffer;
28 import java.nio.charset.Charset;
29 import java.nio.charset.CharsetEncoder;
30 import java.nio.charset.CoderResult;
31 import java.nio.charset.IllegalCharsetNameException;
32 import java.nio.charset.UnsupportedCharsetException;
33 
34 /**
35  * This is a quick and dirty implementation of XmlSerializer that isn't horribly
36  * painfully slow like the normal one.  It only does what is needed for the
37  * specific XML files being written with it.
38  */
39 public class FastXmlSerializer implements XmlSerializer {
40     private static final String ESCAPE_TABLE[] = new String[] {
41         null,     null,     null,     null,     null,     null,     null,     null,  // 0-7
42         null,     null,     null,     null,     null,     null,     null,     null,  // 8-15
43         null,     null,     null,     null,     null,     null,     null,     null,  // 16-23
44         null,     null,     null,     null,     null,     null,     null,     null,  // 24-31
45         null,     null,     """, null,     null,     null,     "&",  null,  // 32-39
46         null,     null,     null,     null,     null,     null,     null,     null,  // 40-47
47         null,     null,     null,     null,     null,     null,     null,     null,  // 48-55
48         null,     null,     null,     null,     "<",   null,     ">",   null,  // 56-63
49     };
50 
51     private static final int BUFFER_LEN = 8192;
52 
53     private final char[] mText = new char[BUFFER_LEN];
54     private int mPos;
55 
56     private Writer mWriter;
57 
58     private OutputStream mOutputStream;
59     private CharsetEncoder mCharset;
60     private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);
61 
62     private boolean mInTag;
63 
append(char c)64     private void append(char c) throws IOException {
65         int pos = mPos;
66         if (pos >= (BUFFER_LEN-1)) {
67             flush();
68             pos = mPos;
69         }
70         mText[pos] = c;
71         mPos = pos+1;
72     }
73 
append(String str, int i, final int length)74     private void append(String str, int i, final int length) throws IOException {
75         if (length > BUFFER_LEN) {
76             final int end = i + length;
77             while (i < end) {
78                 int next = i + BUFFER_LEN;
79                 append(str, i, next<end ? BUFFER_LEN : (end-i));
80                 i = next;
81             }
82             return;
83         }
84         int pos = mPos;
85         if ((pos+length) > BUFFER_LEN) {
86             flush();
87             pos = mPos;
88         }
89         str.getChars(i, i+length, mText, pos);
90         mPos = pos + length;
91     }
92 
append(char[] buf, int i, final int length)93     private void append(char[] buf, int i, final int length) throws IOException {
94         if (length > BUFFER_LEN) {
95             final int end = i + length;
96             while (i < end) {
97                 int next = i + BUFFER_LEN;
98                 append(buf, i, next<end ? BUFFER_LEN : (end-i));
99                 i = next;
100             }
101             return;
102         }
103         int pos = mPos;
104         if ((pos+length) > BUFFER_LEN) {
105             flush();
106             pos = mPos;
107         }
108         System.arraycopy(buf, i, mText, pos, length);
109         mPos = pos + length;
110     }
111 
append(String str)112     private void append(String str) throws IOException {
113         append(str, 0, str.length());
114     }
115 
escapeAndAppendString(final String string)116     private void escapeAndAppendString(final String string) throws IOException {
117         final int N = string.length();
118         final char NE = (char)ESCAPE_TABLE.length;
119         final String[] escapes = ESCAPE_TABLE;
120         int lastPos = 0;
121         int pos;
122         for (pos=0; pos<N; pos++) {
123             char c = string.charAt(pos);
124             if (c >= NE) continue;
125             String escape = escapes[c];
126             if (escape == null) continue;
127             if (lastPos < pos) append(string, lastPos, pos-lastPos);
128             lastPos = pos + 1;
129             append(escape);
130         }
131         if (lastPos < pos) append(string, lastPos, pos-lastPos);
132     }
133 
escapeAndAppendString(char[] buf, int start, int len)134     private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
135         final char NE = (char)ESCAPE_TABLE.length;
136         final String[] escapes = ESCAPE_TABLE;
137         int end = start+len;
138         int lastPos = start;
139         int pos;
140         for (pos=start; pos<end; pos++) {
141             char c = buf[pos];
142             if (c >= NE) continue;
143             String escape = escapes[c];
144             if (escape == null) continue;
145             if (lastPos < pos) append(buf, lastPos, pos-lastPos);
146             lastPos = pos + 1;
147             append(escape);
148         }
149         if (lastPos < pos) append(buf, lastPos, pos-lastPos);
150     }
151 
attribute(String namespace, String name, String value)152     public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
153             IllegalArgumentException, IllegalStateException {
154         append(' ');
155         if (namespace != null) {
156             append(namespace);
157             append(':');
158         }
159         append(name);
160         append("=\"");
161 
162         escapeAndAppendString(value);
163         append('"');
164         return this;
165     }
166 
cdsect(String text)167     public void cdsect(String text) throws IOException, IllegalArgumentException,
168             IllegalStateException {
169         throw new UnsupportedOperationException();
170     }
171 
comment(String text)172     public void comment(String text) throws IOException, IllegalArgumentException,
173             IllegalStateException {
174         throw new UnsupportedOperationException();
175     }
176 
docdecl(String text)177     public void docdecl(String text) throws IOException, IllegalArgumentException,
178             IllegalStateException {
179         throw new UnsupportedOperationException();
180     }
181 
endDocument()182     public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
183         flush();
184     }
185 
endTag(String namespace, String name)186     public XmlSerializer endTag(String namespace, String name) throws IOException,
187             IllegalArgumentException, IllegalStateException {
188         if (mInTag) {
189             append(" />\n");
190         } else {
191             append("</");
192             if (namespace != null) {
193                 append(namespace);
194                 append(':');
195             }
196             append(name);
197             append(">\n");
198         }
199         mInTag = false;
200         return this;
201     }
202 
entityRef(String text)203     public void entityRef(String text) throws IOException, IllegalArgumentException,
204             IllegalStateException {
205         throw new UnsupportedOperationException();
206     }
207 
flushBytes()208     private void flushBytes() throws IOException {
209         int position;
210         if ((position = mBytes.position()) > 0) {
211             mBytes.flip();
212             mOutputStream.write(mBytes.array(), 0, position);
213             mBytes.clear();
214         }
215     }
216 
flush()217     public void flush() throws IOException {
218         //Log.i("PackageManager", "flush mPos=" + mPos);
219         if (mPos > 0) {
220             if (mOutputStream != null) {
221                 CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
222                 CoderResult result = mCharset.encode(charBuffer, mBytes, true);
223                 while (true) {
224                     if (result.isError()) {
225                         throw new IOException(result.toString());
226                     } else if (result.isOverflow()) {
227                         flushBytes();
228                         result = mCharset.encode(charBuffer, mBytes, true);
229                         continue;
230                     }
231                     break;
232                 }
233                 flushBytes();
234                 mOutputStream.flush();
235             } else {
236                 mWriter.write(mText, 0, mPos);
237                 mWriter.flush();
238             }
239             mPos = 0;
240         }
241     }
242 
getDepth()243     public int getDepth() {
244         throw new UnsupportedOperationException();
245     }
246 
getFeature(String name)247     public boolean getFeature(String name) {
248         throw new UnsupportedOperationException();
249     }
250 
getName()251     public String getName() {
252         throw new UnsupportedOperationException();
253     }
254 
getNamespace()255     public String getNamespace() {
256         throw new UnsupportedOperationException();
257     }
258 
getPrefix(String namespace, boolean generatePrefix)259     public String getPrefix(String namespace, boolean generatePrefix)
260             throws IllegalArgumentException {
261         throw new UnsupportedOperationException();
262     }
263 
getProperty(String name)264     public Object getProperty(String name) {
265         throw new UnsupportedOperationException();
266     }
267 
ignorableWhitespace(String text)268     public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
269             IllegalStateException {
270         throw new UnsupportedOperationException();
271     }
272 
processingInstruction(String text)273     public void processingInstruction(String text) throws IOException, IllegalArgumentException,
274             IllegalStateException {
275         throw new UnsupportedOperationException();
276     }
277 
setFeature(String name, boolean state)278     public void setFeature(String name, boolean state) throws IllegalArgumentException,
279             IllegalStateException {
280         if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
281             return;
282         }
283         throw new UnsupportedOperationException();
284     }
285 
setOutput(OutputStream os, String encoding)286     public void setOutput(OutputStream os, String encoding) throws IOException,
287             IllegalArgumentException, IllegalStateException {
288         if (os == null)
289             throw new IllegalArgumentException();
290         if (true) {
291             try {
292                 mCharset = Charset.forName(encoding).newEncoder();
293             } catch (IllegalCharsetNameException e) {
294                 throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
295                         encoding).initCause(e));
296             } catch (UnsupportedCharsetException e) {
297                 throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
298                         encoding).initCause(e));
299             }
300             mOutputStream = os;
301         } else {
302             setOutput(
303                 encoding == null
304                     ? new OutputStreamWriter(os)
305                     : new OutputStreamWriter(os, encoding));
306         }
307     }
308 
setOutput(Writer writer)309     public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
310             IllegalStateException {
311         mWriter = writer;
312     }
313 
setPrefix(String prefix, String namespace)314     public void setPrefix(String prefix, String namespace) throws IOException,
315             IllegalArgumentException, IllegalStateException {
316         throw new UnsupportedOperationException();
317     }
318 
setProperty(String name, Object value)319     public void setProperty(String name, Object value) throws IllegalArgumentException,
320             IllegalStateException {
321         throw new UnsupportedOperationException();
322     }
323 
startDocument(String encoding, Boolean standalone)324     public void startDocument(String encoding, Boolean standalone) throws IOException,
325             IllegalArgumentException, IllegalStateException {
326         append("<?xml version='1.0' encoding='utf-8' standalone='"
327                 + (standalone ? "yes" : "no") + "' ?>\n");
328     }
329 
startTag(String namespace, String name)330     public XmlSerializer startTag(String namespace, String name) throws IOException,
331             IllegalArgumentException, IllegalStateException {
332         if (mInTag) {
333             append(">\n");
334         }
335         append('<');
336         if (namespace != null) {
337             append(namespace);
338             append(':');
339         }
340         append(name);
341         mInTag = true;
342         return this;
343     }
344 
text(char[] buf, int start, int len)345     public XmlSerializer text(char[] buf, int start, int len) throws IOException,
346             IllegalArgumentException, IllegalStateException {
347         if (mInTag) {
348             append(">");
349             mInTag = false;
350         }
351         escapeAndAppendString(buf, start, len);
352         return this;
353     }
354 
text(String text)355     public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
356             IllegalStateException {
357         if (mInTag) {
358             append(">");
359             mInTag = false;
360         }
361         escapeAndAppendString(text);
362         return this;
363     }
364 
365 }
366