aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2023-11-13 19:00:37 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-11-13 19:00:37 +0000
commit2301ba82bf5223c70daa939e296a6a3f7a0bd845 (patch)
tree3101ec479a16787edd7d5c7bf6ae9b9f3410375d
parent9b890ea26224bde80326d90fb3e25d5b9f25abbf (diff)
parenta551bb85deed97ab081bb17652d40d3d3560cab9 (diff)
downloadmodules-utils-2301ba82bf5223c70daa939e296a6a3f7a0bd845.tar.gz
Merge "module-utils: Create fastxmlserializer utility jar" into main am: a551bb85de
Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/modules-utils/+/2819037 Change-Id: I717e021ea47143ea1d975e89bbb156b201da6375 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--java/com/android/internal/util/Android.bp11
-rw-r--r--java/com/android/internal/util/FastXmlSerializer.java424
2 files changed, 435 insertions, 0 deletions
diff --git a/java/com/android/internal/util/Android.bp b/java/com/android/internal/util/Android.bp
index ea21a6b..c2de1fb 100644
--- a/java/com/android/internal/util/Android.bp
+++ b/java/com/android/internal/util/Android.bp
@@ -38,3 +38,14 @@ java_library {
"unsupportedappusage",
],
}
+
+java_library {
+ name: "modules-utils-fastxmlserializer",
+ srcs: [
+ "FastXmlSerializer.java",
+ ],
+ defaults: ["modules-utils-defaults"],
+ libs: [
+ "unsupportedappusage",
+ ],
+}
diff --git a/java/com/android/internal/util/FastXmlSerializer.java b/java/com/android/internal/util/FastXmlSerializer.java
new file mode 100644
index 0000000..929c9e8
--- /dev/null
+++ b/java/com/android/internal/util/FastXmlSerializer.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.compat.annotation.UnsupportedAppUsage;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * This is a quick and dirty implementation of XmlSerializer that isn't horribly
+ * painfully slow like the normal one. It only does what is needed for the
+ * specific XML files being written with it.
+ */
+public class FastXmlSerializer implements XmlSerializer {
+ private static final String ESCAPE_TABLE[] = new String[] {
+ "&#0;", "&#1;", "&#2;", "&#3;", "&#4;", "&#5;", "&#6;", "&#7;", // 0-7
+ "&#8;", "&#9;", "&#10;", "&#11;", "&#12;", "&#13;", "&#14;", "&#15;", // 8-15
+ "&#16;", "&#17;", "&#18;", "&#19;", "&#20;", "&#21;", "&#22;", "&#23;", // 16-23
+ "&#24;", "&#25;", "&#26;", "&#27;", "&#28;", "&#29;", "&#30;", "&#31;", // 24-31
+ null, null, "&quot;", null, null, null, "&amp;", null, // 32-39
+ null, null, null, null, null, null, null, null, // 40-47
+ null, null, null, null, null, null, null, null, // 48-55
+ null, null, null, null, "&lt;", null, "&gt;", null, // 56-63
+ };
+
+ private static final int DEFAULT_BUFFER_LEN = 32*1024;
+
+ private static String sSpace = " ";
+
+ private final int mBufferLen;
+ private final char[] mText;
+ private int mPos;
+
+ private Writer mWriter;
+
+ private OutputStream mOutputStream;
+ private CharsetEncoder mCharset;
+ private ByteBuffer mBytes;
+
+ private boolean mIndent = false;
+ private boolean mInTag;
+
+ private int mNesting = 0;
+ private boolean mLineStart = true;
+
+ @UnsupportedAppUsage
+ public FastXmlSerializer() {
+ this(DEFAULT_BUFFER_LEN);
+ }
+
+ /**
+ * Allocate a FastXmlSerializer with the given internal output buffer size. If the
+ * size is zero or negative, then the default buffer size will be used.
+ *
+ * @param bufferSize Size in bytes of the in-memory output buffer that the writer will use.
+ */
+ public FastXmlSerializer(int bufferSize) {
+ mBufferLen = (bufferSize > 0) ? bufferSize : DEFAULT_BUFFER_LEN;
+ mText = new char[mBufferLen];
+ mBytes = ByteBuffer.allocate(mBufferLen);
+ }
+
+ private void append(char c) throws IOException {
+ int pos = mPos;
+ if (pos >= (mBufferLen-1)) {
+ flush();
+ pos = mPos;
+ }
+ mText[pos] = c;
+ mPos = pos+1;
+ }
+
+ private void append(String str, int i, final int length) throws IOException {
+ if (length > mBufferLen) {
+ final int end = i + length;
+ while (i < end) {
+ int next = i + mBufferLen;
+ append(str, i, next<end ? mBufferLen : (end-i));
+ i = next;
+ }
+ return;
+ }
+ int pos = mPos;
+ if ((pos+length) > mBufferLen) {
+ flush();
+ pos = mPos;
+ }
+ str.getChars(i, i+length, mText, pos);
+ mPos = pos + length;
+ }
+
+ private void append(char[] buf, int i, final int length) throws IOException {
+ if (length > mBufferLen) {
+ final int end = i + length;
+ while (i < end) {
+ int next = i + mBufferLen;
+ append(buf, i, next<end ? mBufferLen : (end-i));
+ i = next;
+ }
+ return;
+ }
+ int pos = mPos;
+ if ((pos+length) > mBufferLen) {
+ flush();
+ pos = mPos;
+ }
+ System.arraycopy(buf, i, mText, pos, length);
+ mPos = pos + length;
+ }
+
+ private void append(String str) throws IOException {
+ append(str, 0, str.length());
+ }
+
+ private void appendIndent(int indent) throws IOException {
+ indent *= 4;
+ if (indent > sSpace.length()) {
+ indent = sSpace.length();
+ }
+ append(sSpace, 0, indent);
+ }
+
+ private void escapeAndAppendString(final String string) throws IOException {
+ final int N = string.length();
+ final char NE = (char)ESCAPE_TABLE.length;
+ final String[] escapes = ESCAPE_TABLE;
+ int lastPos = 0;
+ int pos;
+ for (pos=0; pos<N; pos++) {
+ char c = string.charAt(pos);
+ if (c >= NE) continue;
+ String escape = escapes[c];
+ if (escape == null) continue;
+ if (lastPos < pos) append(string, lastPos, pos-lastPos);
+ lastPos = pos + 1;
+ append(escape);
+ }
+ if (lastPos < pos) append(string, lastPos, pos-lastPos);
+ }
+
+ private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
+ final char NE = (char)ESCAPE_TABLE.length;
+ final String[] escapes = ESCAPE_TABLE;
+ int end = start+len;
+ int lastPos = start;
+ int pos;
+ for (pos=start; pos<end; pos++) {
+ char c = buf[pos];
+ if (c >= NE) continue;
+ String escape = escapes[c];
+ if (escape == null) continue;
+ if (lastPos < pos) append(buf, lastPos, pos-lastPos);
+ lastPos = pos + 1;
+ append(escape);
+ }
+ if (lastPos < pos) append(buf, lastPos, pos-lastPos);
+ }
+
+ public XmlSerializer attribute(String namespace, String name, String value) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ append(' ');
+ if (namespace != null) {
+ append(namespace);
+ append(':');
+ }
+ append(name);
+ append("=\"");
+
+ escapeAndAppendString(value);
+ append('"');
+ mLineStart = false;
+ return this;
+ }
+
+ public void cdsect(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void comment(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void docdecl(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
+ flush();
+ }
+
+ public XmlSerializer endTag(String namespace, String name) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ mNesting--;
+ if (mInTag) {
+ append(" />\n");
+ } else {
+ if (mIndent && mLineStart) {
+ appendIndent(mNesting);
+ }
+ append("</");
+ if (namespace != null) {
+ append(namespace);
+ append(':');
+ }
+ append(name);
+ append(">\n");
+ }
+ mLineStart = true;
+ mInTag = false;
+ return this;
+ }
+
+ public void entityRef(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ private void flushBytes() throws IOException {
+ int position;
+ if ((position = mBytes.position()) > 0) {
+ mBytes.flip();
+ mOutputStream.write(mBytes.array(), 0, position);
+ mBytes.clear();
+ }
+ }
+
+ public void flush() throws IOException {
+ //Log.i("PackageManager", "flush mPos=" + mPos);
+ if (mPos > 0) {
+ if (mOutputStream != null) {
+ CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
+ CoderResult result = mCharset.encode(charBuffer, mBytes, true);
+ while (true) {
+ if (result.isError()) {
+ throw new IOException(result.toString());
+ } else if (result.isOverflow()) {
+ flushBytes();
+ result = mCharset.encode(charBuffer, mBytes, true);
+ continue;
+ }
+ break;
+ }
+ flushBytes();
+ mOutputStream.flush();
+ } else {
+ mWriter.write(mText, 0, mPos);
+ mWriter.flush();
+ }
+ mPos = 0;
+ }
+ }
+
+ public int getDepth() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getFeature(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getName() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getNamespace() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPrefix(String namespace, boolean generatePrefix)
+ throws IllegalArgumentException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getProperty(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void processingInstruction(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setFeature(String name, boolean state) throws IllegalArgumentException,
+ IllegalStateException {
+ if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
+ mIndent = true;
+ return;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public void setOutput(OutputStream os, String encoding) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ if (os == null)
+ throw new IllegalArgumentException();
+ if (true) {
+ try {
+ mCharset = Charset.forName(encoding).newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ } catch (IllegalCharsetNameException e) {
+ throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
+ encoding).initCause(e));
+ } catch (UnsupportedCharsetException e) {
+ throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
+ encoding).initCause(e));
+ }
+ mOutputStream = os;
+ } else {
+ setOutput(
+ encoding == null
+ ? new OutputStreamWriter(os)
+ : new OutputStreamWriter(os, encoding));
+ }
+ }
+
+ public void setOutput(Writer writer) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ mWriter = writer;
+ }
+
+ public void setPrefix(String prefix, String namespace) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setProperty(String name, Object value) throws IllegalArgumentException,
+ IllegalStateException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void startDocument(String encoding, Boolean standalone) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ append("<?xml version='1.0' encoding='utf-8'");
+ if (standalone != null) {
+ append(" standalone='" + (standalone ? "yes" : "no") + "'");
+ }
+ append(" ?>\n");
+ mLineStart = true;
+ }
+
+ public XmlSerializer startTag(String namespace, String name) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ if (mInTag) {
+ append(">\n");
+ }
+ if (mIndent) {
+ appendIndent(mNesting);
+ }
+ mNesting++;
+ append('<');
+ if (namespace != null) {
+ append(namespace);
+ append(':');
+ }
+ append(name);
+ mInTag = true;
+ mLineStart = false;
+ return this;
+ }
+
+ public XmlSerializer text(char[] buf, int start, int len) throws IOException,
+ IllegalArgumentException, IllegalStateException {
+ if (mInTag) {
+ append(">");
+ mInTag = false;
+ }
+ escapeAndAppendString(buf, start, len);
+ if (mIndent) {
+ mLineStart = buf[start+len-1] == '\n';
+ }
+ return this;
+ }
+
+ public XmlSerializer text(String text) throws IOException, IllegalArgumentException,
+ IllegalStateException {
+ if (mInTag) {
+ append(">");
+ mInTag = false;
+ }
+ escapeAndAppendString(text);
+ if (mIndent) {
+ mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\n');
+ }
+ return this;
+ }
+
+}