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

Commit febae4ed authored by Jesse Wilson's avatar Jesse Wilson
Browse files

Track line and column when parsing JSON.

This is a prerequisite to skipping the BOM if it exists.
Bug: http://code.google.com/p/android/issues/detail?id=18508

Change-Id: I38b1c46f246d8526fa20859b50ca3e25c9f9b9d1
parent 2ad31117
Loading
Loading
Loading
Loading
+40 −1
Original line number Diff line number Diff line
@@ -196,6 +196,12 @@ public final class JsonReader implements Closeable {
    private int pos = 0;
    private int limit = 0;

    /*
     * The offset of the first character in the buffer.
     */
    private int bufferStartLine = 1;
    private int bufferStartColumn = 1;

    private final List<JsonScope> stack = new ArrayList<JsonScope>();
    {
        push(JsonScope.EMPTY_DOCUMENT);
@@ -711,6 +717,16 @@ public final class JsonReader implements Closeable {
     * false.
     */
    private boolean fillBuffer(int minimum) throws IOException {
        // Before clobbering the old characters, update where buffer starts
        for (int i = 0; i < pos; i++) {
            if (buffer[i] == '\n') {
                bufferStartLine++;
                bufferStartColumn = 1;
            } else {
                bufferStartColumn++;
            }
        }

        if (limit != pos) {
            limit -= pos;
            System.arraycopy(buffer, pos, buffer, 0, limit);
@@ -729,6 +745,28 @@ public final class JsonReader implements Closeable {
        return false;
    }

    private int getLineNumber() {
        int result = bufferStartLine;
        for (int i = 0; i < pos; i++) {
            if (buffer[i] == '\n') {
                result++;
            }
        }
        return result;
    }

    private int getColumnNumber() {
        int result = bufferStartColumn;
        for (int i = 0; i < pos; i++) {
            if (buffer[i] == '\n') {
                result = 1;
            } else {
                result++;
            }
        }
        return result;
    }

    private int nextNonWhitespace() throws IOException {
        while (pos < limit || fillBuffer(1)) {
            int c = buffer[pos++];
@@ -1107,7 +1145,8 @@ public final class JsonReader implements Closeable {
     * with this reader's content.
     */
    private IOException syntaxError(String message) throws IOException {
        throw new MalformedJsonException(message + " near " + getSnippet());
        throw new MalformedJsonException(message
                + " at line " + getLineNumber() + " column " + getColumnNumber());
    }

    private CharSequence getSnippet() {
+29 −0
Original line number Diff line number Diff line
@@ -856,4 +856,33 @@ public final class JsonReaderTest extends TestCase {
        } catch (IOException expected) {
        }
    }

    public void testFailWithPosition() throws IOException {
        testFailWithPosition("Expected literal value at line 6 column   3",
                "[\n\n\n\n\n0,}]");
    }

    public void testFailWithPositionGreaterThanBufferSize() throws IOException {
        String spaces = repeat(' ', 8192);
        testFailWithPosition("Expected literal value at line 6 column 3",
                "[\n\n" + spaces + "\n\n\n0,}]");
    }

    private void testFailWithPosition(String message, String json) throws IOException {
        JsonReader reader = new JsonReader(new StringReader(json));
        reader.beginArray();
        reader.nextInt();
        try {
            reader.peek();
            fail();
        } catch (IOException expected) {
            assertEquals(message, expected.getMessage());
        }
    }

    private String repeat(char c, int count) {
        char[] array = new char[count];
        Arrays.fill(array, c);
        return new String(array);
    }
}