From befcfd908b55f1ee80eb046fe6c1196e49491ab2 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 20 Jul 2011 18:57:30 +0000 Subject: [PATCH] Skip a byte order mark (BOM) if it exists. http://code.google.com/p/android/issues/detail?id=18508 --- .../com/google/gson/stream/JsonReader.java | 26 +++++++++------ .../google/gson/stream/JsonReaderTest.java | 33 +++++++++++++++---- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/gson/src/main/java/com/google/gson/stream/JsonReader.java b/gson/src/main/java/com/google/gson/stream/JsonReader.java index a936ddf9..6eb360c2 100644 --- a/gson/src/main/java/com/google/gson/stream/JsonReader.java +++ b/gson/src/main/java/com/google/gson/stream/JsonReader.java @@ -205,12 +205,10 @@ public final class JsonReader implements Closeable { private int limit = 0; /* - * Track the number of newlines and columns preceding the current buffer. To - * compute the line and column of a position in the buffer, compute the line - * and column in the buffer and add the preceding values. + * The offset of the first character in the buffer. */ - private int bufferStartLine; - private int bufferStartColumn; + private int bufferStartLine = 1; + private int bufferStartColumn = 1; private final List stack = new ArrayList(); { @@ -829,7 +827,7 @@ public final class JsonReader implements Closeable { for (int i = 0; i < pos; i++) { if (buffer[i] == '\n') { bufferStartLine++; - bufferStartColumn = 0; + bufferStartColumn = 1; } else { bufferStartColumn++; } @@ -846,6 +844,13 @@ public final class JsonReader implements Closeable { int total; while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) { limit += total; + + // if this is the first read, consume an optional byte order mark (BOM) if it exists + if (bufferStartLine == 1 && bufferStartColumn == 1 && limit > 1 && buffer[0] == '\ufeff') { + pos++; + bufferStartColumn--; + } + if (limit >= minimum) { return true; } @@ -860,19 +865,19 @@ public final class JsonReader implements Closeable { result++; } } - return result + 1; // the first line is '1' + return result; } private int getColumnNumber() { int result = bufferStartColumn; for (int i = 0; i < pos; i++) { if (buffer[i] == '\n') { - result = 0; + result = 1; } else { result++; } } - return result + 1; // the first column is '1' + return result; } private int nextNonWhitespace() throws IOException { @@ -1150,7 +1155,8 @@ public final class JsonReader implements Closeable { * with this reader's content. */ private IOException syntaxError(String message) throws IOException { - throw new MalformedJsonException(message + " @" + getLineNumber() + ":" + getColumnNumber()); + throw new MalformedJsonException(message + + " at line " + getLineNumber() + " column " + getColumnNumber()); } private CharSequence getSnippet() { diff --git a/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java b/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java index d7e6a0b9..fd296657 100644 --- a/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java +++ b/gson/src/test/java/com/google/gson/stream/JsonReaderTest.java @@ -765,28 +765,47 @@ public final class JsonReaderTest extends TestCase { } } - public void testFailWithPosition() throws IOException { - JsonReader reader = new JsonReader(new StringReader("[\n\n\n\n\n0,}]")); + public void testBomIgnoredAsFirstCharacterOfDocument() throws IOException { + JsonReader reader = new JsonReader(new StringReader("\ufeff[]")); + reader.beginArray(); + reader.endArray(); + } + + public void testBomForbiddenAsOtherCharacterInDocument() throws IOException { + JsonReader reader = new JsonReader(new StringReader("[\ufeff]")); reader.beginArray(); - reader.nextInt(); try { - reader.peek(); + reader.endArray(); fail(); } catch (IOException expected) { - assertEquals("Expected literal value @6:3", expected.getMessage()); } } + 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); - JsonReader reader = new JsonReader(new StringReader("[\n\n" + spaces + "\n\n\n0,}]")); + testFailWithPosition("Expected literal value at line 6 column 3", + "[\n\n" + spaces + "\n\n\n0,}]"); + } + + public void testFailWithPositionIsOffsetByBom() throws IOException { + testFailWithPosition("Expected literal value at line 1 column 4", + "\ufeff[0,}]"); + } + + 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("Expected literal value @6:3", expected.getMessage()); + assertEquals(message, expected.getMessage()); } }