Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca94f293 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Make FastXmlSerializer more suitable to persist arbitrary strings" into nyc-dev

parents b7da9ce4 3ae3557e
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ 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;

@@ -38,10 +39,10 @@ import java.nio.charset.UnsupportedCharsetException;
 */
public class FastXmlSerializer implements XmlSerializer {
    private static final String ESCAPE_TABLE[] = new String[] {
        null,     null,     null,     null,     null,     null,     null,     null,  // 0-7
        null,     null,     null,     null,     null,     null,     null,     null,  // 8-15
        null,     null,     null,     null,     null,     null,     null,     null,  // 16-23
        null,     null,     null,     null,     null,     null,     null,     null,  // 24-31
        "�",   "",   "",   "",  "",    "",   "",  "",  // 0-7
        "",   "	",   "
",  "", "",   "
",  "", "", // 8-15
        "",  "",  "",  "", "",   "",  "", "", // 16-23
        "",  "",  "",  "", "",   "",  "", "", // 24-31
        null,     null,     """, null,     null,     null,     "&",  null,   // 32-39
        null,     null,     null,     null,     null,     null,     null,     null,   // 40-47
        null,     null,     null,     null,     null,     null,     null,     null,   // 48-55
@@ -310,7 +311,9 @@ public class FastXmlSerializer implements XmlSerializer {
            throw new IllegalArgumentException();
        if (true) {
            try {
                mCharset = Charset.forName(encoding).newEncoder();
                mCharset = Charset.forName(encoding).newEncoder()
                        .onMalformedInput(CodingErrorAction.REPLACE)
                        .onUnmappableCharacter(CodingErrorAction.REPLACE);
            } catch (IllegalCharsetNameException e) {
                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(
                        encoding).initCause(e));
+105 −0
Original line number Diff line number Diff line
@@ -16,16 +16,32 @@

package com.android.internal.util;

import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.Xml;

import junit.framework.TestCase;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;

/**
 * Tests for {@link FastXmlSerializer}
 */
@SmallTest
public class FastXmlSerializerTest extends TestCase {
    private static final String TAG = "FastXmlSerializerTest";

    private static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH TRUE.

    private static final String ROOT_TAG = "root";
    private static final String ATTR = "attr";

    public void testEmptyText() throws Exception {
        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

@@ -44,4 +60,93 @@ public class FastXmlSerializerTest extends TestCase {
        assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                + "<string name=\"meow\"></string>\n", stream.toString());
    }

    private boolean checkPreserved(String description, String str) {
        boolean ok = true;
        byte[] data;
        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            final XmlSerializer out = new FastXmlSerializer();
            out.setOutput(baos, StandardCharsets.UTF_16.name());
            out.startDocument(null, true);

            out.startTag(null, ROOT_TAG);
            out.attribute(null, ATTR, str);
            out.text(str);
            out.endTag(null, ROOT_TAG);

            out.endDocument();
            baos.flush();
            data = baos.toByteArray();
        } catch (Exception e) {
            Log.e(TAG, "Unable to serialize: " + description, e);
            return false;
        }

        if (ENABLE_DUMP) {
            Log.d(TAG, "Dump:");
            Log.d(TAG, new String(data));
        }

        try (final ByteArrayInputStream baos = new ByteArrayInputStream(data)) {
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(baos, StandardCharsets.UTF_16.name());

            int type;
            String tag = null;
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                if (type == XmlPullParser.START_TAG) {
                    tag = parser.getName();
                    if (ROOT_TAG.equals(tag)) {
                        String read = parser.getAttributeValue(null, ATTR);
                        if (!str.equals(read)) {
                            Log.e(TAG, "Attribute not preserved: " + description
                                    + " input=\"" + str + "\", but read=\"" + read + "\"");
                            ok = false;
                        }
                    }
                }
                if (type == XmlPullParser.TEXT && ROOT_TAG.equals(tag)) {
                    String read = parser.getText();
                    if (!str.equals(parser.getText())) {
                        Log.e(TAG, "Text not preserved: " + description
                                + " input=\"" + str + "\", but read=\"" + read + "\"");
                        ok = false;
                    }
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "Unable to parse: " + description, e);
            return false;
        }
        return ok;
    }

    private boolean check(String description, String str) throws Exception {
        boolean ok = false;
        ok |= checkPreserved(description, str);
        ok |= checkPreserved(description + " wrapped with spaces" ,"  " + str + "  ");
        return ok;
    }

    @LargeTest
    public void testAllCharacters() throws Exception {
        boolean ok = true;
        for (int i = 0; i < 0xffff; i++) {
            if (0xd800 <= i && i <= 0xdfff) {
                // Surrogate pair characters.
                continue;
            }
            ok &= check("char: " + i, String.valueOf((char) i));
        }
        // Dangling surrogate pairs. We can't preserve them.
        assertFalse(check("+ud800", "\ud800"));
        assertFalse(check("+udc00", "\udc00"));

        for (int i = 0xd800; i < 0xdc00; i ++) {
            for (int j = 0xdc00; j < 0xe000; j++) {
                ok &= check("char: " + i, String.valueOf((char) i) + String.valueOf((char) j));
            }
        }
        assertTrue("Some tests failed.  See logcat for details.", ok);
    }
}