Skip a byte order mark (BOM) if it exists.

http://code.google.com/p/android/issues/detail?id=18508
This commit is contained in:
Jesse Wilson 2011-07-20 18:57:30 +00:00
parent 415437810a
commit befcfd908b
2 changed files with 42 additions and 17 deletions

View File

@ -205,12 +205,10 @@ public final class JsonReader implements Closeable {
private int limit = 0; private int limit = 0;
/* /*
* Track the number of newlines and columns preceding the current buffer. To * The offset of the first character in the buffer.
* compute the line and column of a position in the buffer, compute the line
* and column in the buffer and add the preceding values.
*/ */
private int bufferStartLine; private int bufferStartLine = 1;
private int bufferStartColumn; private int bufferStartColumn = 1;
private final List<JsonScope> stack = new ArrayList<JsonScope>(); private final List<JsonScope> stack = new ArrayList<JsonScope>();
{ {
@ -829,7 +827,7 @@ public final class JsonReader implements Closeable {
for (int i = 0; i < pos; i++) { for (int i = 0; i < pos; i++) {
if (buffer[i] == '\n') { if (buffer[i] == '\n') {
bufferStartLine++; bufferStartLine++;
bufferStartColumn = 0; bufferStartColumn = 1;
} else { } else {
bufferStartColumn++; bufferStartColumn++;
} }
@ -846,6 +844,13 @@ public final class JsonReader implements Closeable {
int total; int total;
while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) { while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) {
limit += total; 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) { if (limit >= minimum) {
return true; return true;
} }
@ -860,19 +865,19 @@ public final class JsonReader implements Closeable {
result++; result++;
} }
} }
return result + 1; // the first line is '1' return result;
} }
private int getColumnNumber() { private int getColumnNumber() {
int result = bufferStartColumn; int result = bufferStartColumn;
for (int i = 0; i < pos; i++) { for (int i = 0; i < pos; i++) {
if (buffer[i] == '\n') { if (buffer[i] == '\n') {
result = 0; result = 1;
} else { } else {
result++; result++;
} }
} }
return result + 1; // the first column is '1' return result;
} }
private int nextNonWhitespace() throws IOException { private int nextNonWhitespace() throws IOException {
@ -1150,7 +1155,8 @@ public final class JsonReader implements Closeable {
* with this reader's content. * with this reader's content.
*/ */
private IOException syntaxError(String message) throws IOException { 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() { private CharSequence getSnippet() {

View File

@ -765,28 +765,47 @@ public final class JsonReaderTest extends TestCase {
} }
} }
public void testFailWithPosition() throws IOException { public void testBomIgnoredAsFirstCharacterOfDocument() throws IOException {
JsonReader reader = new JsonReader(new StringReader("[\n\n\n\n\n0,}]")); 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.beginArray();
reader.nextInt();
try { try {
reader.peek(); reader.endArray();
fail(); fail();
} catch (IOException expected) { } 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 { public void testFailWithPositionGreaterThanBufferSize() throws IOException {
String spaces = repeat(' ', 8192); 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.beginArray();
reader.nextInt(); reader.nextInt();
try { try {
reader.peek(); reader.peek();
fail(); fail();
} catch (IOException expected) { } catch (IOException expected) {
assertEquals("Expected literal value @6:3", expected.getMessage()); assertEquals(message, expected.getMessage());
} }
} }