mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
Merge pull request #3 from square/jwilson_0810_indexOfElement
Use indexOfElement in JsonReader.
This commit is contained in:
@@ -16,7 +16,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.squareup.okio</groupId>
|
<groupId>com.squareup.okio</groupId>
|
||||||
<artifactId>okio</artifactId>
|
<artifactId>okio</artifactId>
|
||||||
<version>1.0.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
|
@@ -20,6 +20,7 @@ import java.io.EOFException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import okio.Buffer;
|
import okio.Buffer;
|
||||||
import okio.BufferedSource;
|
import okio.BufferedSource;
|
||||||
|
import okio.ByteString;
|
||||||
import okio.Source;
|
import okio.Source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,6 +177,12 @@ import okio.Source;
|
|||||||
public class JsonReader implements Closeable {
|
public class JsonReader implements Closeable {
|
||||||
private static final long MIN_INCOMPLETE_INTEGER = Long.MIN_VALUE / 10;
|
private static final long MIN_INCOMPLETE_INTEGER = Long.MIN_VALUE / 10;
|
||||||
|
|
||||||
|
private static final ByteString SINGLE_QUOTE_OR_SLASH = ByteString.encodeUtf8("'\\");
|
||||||
|
private static final ByteString DOUBLE_QUOTE_OR_SLASH = ByteString.encodeUtf8("\"\\");
|
||||||
|
private static final ByteString UNQUOTED_STRING_TERMINALS
|
||||||
|
= ByteString.encodeUtf8("{}[]:, \n\t\r\f/\\;#=");
|
||||||
|
private static final ByteString LINEFEED_OR_CARRIAGE_RETURN = ByteString.encodeUtf8("\n\r");
|
||||||
|
|
||||||
private static final int PEEKED_NONE = 0;
|
private static final int PEEKED_NONE = 0;
|
||||||
private static final int PEEKED_BEGIN_OBJECT = 1;
|
private static final int PEEKED_BEGIN_OBJECT = 1;
|
||||||
private static final int PEEKED_END_OBJECT = 2;
|
private static final int PEEKED_END_OBJECT = 2;
|
||||||
@@ -271,7 +278,7 @@ public class JsonReader implements Closeable {
|
|||||||
*/
|
*/
|
||||||
public JsonReader(String s) {
|
public JsonReader(String s) {
|
||||||
this.source = new Buffer().writeUtf8(s);
|
this.source = new Buffer().writeUtf8(s);
|
||||||
this.buffer = new Buffer();
|
this.buffer = source.buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -561,7 +568,7 @@ public class JsonReader implements Closeable {
|
|||||||
buffer.readByte(); // Consume '['.
|
buffer.readByte(); // Consume '['.
|
||||||
return peeked = PEEKED_BEGIN_ARRAY;
|
return peeked = PEEKED_BEGIN_ARRAY;
|
||||||
case '{':
|
case '{':
|
||||||
buffer.readByte(); // Consume ']'.
|
buffer.readByte(); // Consume '{'.
|
||||||
return peeked = PEEKED_BEGIN_OBJECT;
|
return peeked = PEEKED_BEGIN_OBJECT;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@@ -760,10 +767,10 @@ public class JsonReader implements Closeable {
|
|||||||
String result;
|
String result;
|
||||||
if (p == PEEKED_UNQUOTED_NAME) {
|
if (p == PEEKED_UNQUOTED_NAME) {
|
||||||
result = nextUnquotedValue();
|
result = nextUnquotedValue();
|
||||||
} else if (p == PEEKED_SINGLE_QUOTED_NAME) {
|
|
||||||
result = nextQuotedValue('\'');
|
|
||||||
} else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
|
} else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
|
||||||
result = nextQuotedValue('"');
|
result = nextQuotedValue(DOUBLE_QUOTE_OR_SLASH);
|
||||||
|
} else if (p == PEEKED_SINGLE_QUOTED_NAME) {
|
||||||
|
result = nextQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected a name but was " + peek()
|
throw new IllegalStateException("Expected a name but was " + peek()
|
||||||
+ " at path " + getPath());
|
+ " at path " + getPath());
|
||||||
@@ -789,10 +796,10 @@ public class JsonReader implements Closeable {
|
|||||||
String result;
|
String result;
|
||||||
if (p == PEEKED_UNQUOTED) {
|
if (p == PEEKED_UNQUOTED) {
|
||||||
result = nextUnquotedValue();
|
result = nextUnquotedValue();
|
||||||
} else if (p == PEEKED_SINGLE_QUOTED) {
|
|
||||||
result = nextQuotedValue('\'');
|
|
||||||
} else if (p == PEEKED_DOUBLE_QUOTED) {
|
} else if (p == PEEKED_DOUBLE_QUOTED) {
|
||||||
result = nextQuotedValue('"');
|
result = nextQuotedValue(DOUBLE_QUOTE_OR_SLASH);
|
||||||
|
} else if (p == PEEKED_SINGLE_QUOTED) {
|
||||||
|
result = nextQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||||
} else if (p == PEEKED_BUFFERED) {
|
} else if (p == PEEKED_BUFFERED) {
|
||||||
result = peekedString;
|
result = peekedString;
|
||||||
peekedString = null;
|
peekedString = null;
|
||||||
@@ -878,8 +885,10 @@ public class JsonReader implements Closeable {
|
|||||||
|
|
||||||
if (p == PEEKED_NUMBER) {
|
if (p == PEEKED_NUMBER) {
|
||||||
peekedString = buffer.readUtf8(peekedNumberLength);
|
peekedString = buffer.readUtf8(peekedNumberLength);
|
||||||
} else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
|
} else if (p == PEEKED_DOUBLE_QUOTED) {
|
||||||
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
|
peekedString = nextQuotedValue(DOUBLE_QUOTE_OR_SLASH);
|
||||||
|
} else if (p == PEEKED_SINGLE_QUOTED) {
|
||||||
|
peekedString = nextQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||||
} else if (p == PEEKED_UNQUOTED) {
|
} else if (p == PEEKED_UNQUOTED) {
|
||||||
peekedString = nextUnquotedValue();
|
peekedString = nextUnquotedValue();
|
||||||
} else if (p != PEEKED_BUFFERED) {
|
} else if (p != PEEKED_BUFFERED) {
|
||||||
@@ -923,8 +932,10 @@ public class JsonReader implements Closeable {
|
|||||||
|
|
||||||
if (p == PEEKED_NUMBER) {
|
if (p == PEEKED_NUMBER) {
|
||||||
peekedString = buffer.readUtf8(peekedNumberLength);
|
peekedString = buffer.readUtf8(peekedNumberLength);
|
||||||
} else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
|
} else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED) {
|
||||||
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
|
peekedString = p == PEEKED_DOUBLE_QUOTED
|
||||||
|
? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
|
||||||
|
: nextQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||||
try {
|
try {
|
||||||
long result = Long.parseLong(peekedString);
|
long result = Long.parseLong(peekedString);
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
@@ -957,109 +968,61 @@ public class JsonReader implements Closeable {
|
|||||||
* should have already been read. This consumes the closing quote, but does
|
* should have already been read. This consumes the closing quote, but does
|
||||||
* not include it in the returned string.
|
* not include it in the returned string.
|
||||||
*
|
*
|
||||||
* @param quote either ' or ".
|
|
||||||
* @throws NumberFormatException if any unicode escape sequences are
|
* @throws NumberFormatException if any unicode escape sequences are
|
||||||
* malformed.
|
* malformed.
|
||||||
*/
|
*/
|
||||||
private String nextQuotedValue(char quote) throws IOException {
|
private String nextQuotedValue(ByteString runTerminator) throws IOException {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = null;
|
||||||
int p = 0;
|
while (true) {
|
||||||
while (fillBuffer(p + 1)) {
|
long index = source.indexOfElement(runTerminator);
|
||||||
int c = buffer.getByte(p++);
|
if (index == -1L) throw syntaxError("Unterminated string");
|
||||||
|
|
||||||
if (c == quote) {
|
// If we've got an escape character, we're going to need a string builder.
|
||||||
builder.append(buffer.readUtf8(p - 1));
|
if (buffer.getByte(index) == '\\') {
|
||||||
buffer.readByte();
|
if (builder == null) builder = new StringBuilder();
|
||||||
return builder.toString();
|
builder.append(buffer.readUtf8(index));
|
||||||
} else if (c == '\\') {
|
|
||||||
builder.append(buffer.readUtf8(p - 1));
|
|
||||||
buffer.readByte(); // '\'
|
buffer.readByte(); // '\'
|
||||||
builder.append(readEscapeCharacter());
|
builder.append(readEscapeCharacter());
|
||||||
p = 0;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it isn't the escape character, it's the quote. Return the string.
|
||||||
|
if (builder == null) {
|
||||||
|
String result = buffer.readUtf8(index);
|
||||||
|
buffer.readByte(); // Consume the quote character.
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
builder.append(buffer.readUtf8(index));
|
||||||
|
buffer.readByte(); // Consume the quote character.
|
||||||
|
return builder.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw syntaxError("Unterminated string");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns an unquoted value as a string. */
|
||||||
* Returns an unquoted value as a string.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
private String nextUnquotedValue() throws IOException {
|
private String nextUnquotedValue() throws IOException {
|
||||||
int i = 0;
|
long i = source.indexOfElement(UNQUOTED_STRING_TERMINALS);
|
||||||
|
return i != -1 ? buffer.readUtf8(i) : buffer.readUtf8();
|
||||||
findNonStringChar:
|
|
||||||
for (; fillBuffer(i + 1); i++) {
|
|
||||||
switch (buffer.getByte(i)) {
|
|
||||||
case '/':
|
|
||||||
case '\\':
|
|
||||||
case ';':
|
|
||||||
case '#':
|
|
||||||
case '=':
|
|
||||||
checkLenient(); // fall-through
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
case ':':
|
|
||||||
case ',':
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\f':
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
break findNonStringChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.readUtf8(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skipQuotedValue(char quote) throws IOException {
|
private void skipQuotedValue(ByteString runTerminator) throws IOException {
|
||||||
int p = 0;
|
while (true) {
|
||||||
while (fillBuffer(p + 1)) {
|
long index = source.indexOfElement(runTerminator);
|
||||||
int c = buffer.getByte(p++);
|
if (index == -1L) throw syntaxError("Unterminated string");
|
||||||
if (c == quote) {
|
|
||||||
buffer.skip(p);
|
if (buffer.getByte(index) == '\\') {
|
||||||
return;
|
buffer.skip(index + 1);
|
||||||
} else if (c == '\\') {
|
|
||||||
buffer.skip(p);
|
|
||||||
readEscapeCharacter();
|
readEscapeCharacter();
|
||||||
p = 0;
|
} else {
|
||||||
|
buffer.skip(index + 1);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw syntaxError("Unterminated string");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void skipUnquotedValue() throws IOException {
|
private void skipUnquotedValue() throws IOException {
|
||||||
int i = 0;
|
long i = source.indexOfElement(UNQUOTED_STRING_TERMINALS);
|
||||||
|
buffer.skip(i != -1L ? i : buffer.size());
|
||||||
findNonStringChar:
|
|
||||||
for (; fillBuffer(i + 1); i++) {
|
|
||||||
switch (buffer.getByte(i)) {
|
|
||||||
case '/':
|
|
||||||
case '\\':
|
|
||||||
case ';':
|
|
||||||
case '#':
|
|
||||||
case '=':
|
|
||||||
checkLenient(); // fall-through
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
case ':':
|
|
||||||
case ',':
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\f':
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
break findNonStringChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.skip(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1092,8 +1055,10 @@ public class JsonReader implements Closeable {
|
|||||||
|
|
||||||
if (p == PEEKED_NUMBER) {
|
if (p == PEEKED_NUMBER) {
|
||||||
peekedString = buffer.readUtf8(peekedNumberLength);
|
peekedString = buffer.readUtf8(peekedNumberLength);
|
||||||
} else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
|
} else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_SINGLE_QUOTED) {
|
||||||
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
|
peekedString = p == PEEKED_DOUBLE_QUOTED
|
||||||
|
? nextQuotedValue(DOUBLE_QUOTE_OR_SLASH)
|
||||||
|
: nextQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||||
try {
|
try {
|
||||||
result = Integer.parseInt(peekedString);
|
result = Integer.parseInt(peekedString);
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
@@ -1158,10 +1123,10 @@ public class JsonReader implements Closeable {
|
|||||||
count--;
|
count--;
|
||||||
} else if (p == PEEKED_UNQUOTED_NAME || p == PEEKED_UNQUOTED) {
|
} else if (p == PEEKED_UNQUOTED_NAME || p == PEEKED_UNQUOTED) {
|
||||||
skipUnquotedValue();
|
skipUnquotedValue();
|
||||||
} else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_SINGLE_QUOTED_NAME) {
|
|
||||||
skipQuotedValue('\'');
|
|
||||||
} else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_DOUBLE_QUOTED_NAME) {
|
} else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_DOUBLE_QUOTED_NAME) {
|
||||||
skipQuotedValue('"');
|
skipQuotedValue(DOUBLE_QUOTE_OR_SLASH);
|
||||||
|
} else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_SINGLE_QUOTED_NAME) {
|
||||||
|
skipQuotedValue(SINGLE_QUOTE_OR_SLASH);
|
||||||
} else if (p == PEEKED_NUMBER) {
|
} else if (p == PEEKED_NUMBER) {
|
||||||
buffer.skip(peekedNumberLength);
|
buffer.skip(peekedNumberLength);
|
||||||
}
|
}
|
||||||
@@ -1193,10 +1158,7 @@ public class JsonReader implements Closeable {
|
|||||||
* false.
|
* false.
|
||||||
*/
|
*/
|
||||||
private boolean fillBuffer(int minimum) throws IOException {
|
private boolean fillBuffer(int minimum) throws IOException {
|
||||||
while (buffer.size() < minimum) {
|
return source.request(minimum);
|
||||||
if (source.read(buffer, 2048) == -1) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1285,12 +1247,8 @@ public class JsonReader implements Closeable {
|
|||||||
* caller.
|
* caller.
|
||||||
*/
|
*/
|
||||||
private void skipToEndOfLine() throws IOException {
|
private void skipToEndOfLine() throws IOException {
|
||||||
while (fillBuffer(1)) {
|
long index = source.indexOfElement(LINEFEED_OR_CARRIAGE_RETURN);
|
||||||
byte c = buffer.readByte();
|
buffer.skip(index != -1 ? index + 1 : buffer.size());
|
||||||
if (c == '\n' || c == '\r') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -17,8 +17,6 @@ package com.squareup.moshi;
|
|||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import okio.Source;
|
import okio.Source;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
@@ -895,6 +893,11 @@ public final class JsonReaderTest {
|
|||||||
reader.setLenient(true);
|
reader.setLenient(true);
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
assertEquals(true, reader.nextBoolean());
|
assertEquals(true, reader.nextBoolean());
|
||||||
|
|
||||||
|
reader = new JsonReader("a//");
|
||||||
|
reader.setLenient(true);
|
||||||
|
assertEquals("a", reader.nextString());
|
||||||
|
assertEquals(JsonToken.END_DOCUMENT, reader.peek());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void strictCommentsWithSkipValue() throws IOException {
|
@Test public void strictCommentsWithSkipValue() throws IOException {
|
||||||
@@ -1011,6 +1014,14 @@ public final class JsonReaderTest {
|
|||||||
assertEquals("a", reader.nextString());
|
assertEquals("a", reader.nextString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void lenientUnquotedStringsDelimitedByComment() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader("[a#comment\n]");
|
||||||
|
reader.setLenient(true);
|
||||||
|
reader.beginArray();
|
||||||
|
assertEquals("a", reader.nextString());
|
||||||
|
reader.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void strictSingleQuotedStrings() throws IOException {
|
@Test public void strictSingleQuotedStrings() throws IOException {
|
||||||
JsonReader reader = new JsonReader("['a']");
|
JsonReader reader = new JsonReader("['a']");
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
|
7
pom.xml
7
pom.xml
@@ -26,7 +26,7 @@
|
|||||||
<java.version>1.6</java.version>
|
<java.version>1.6</java.version>
|
||||||
|
|
||||||
<!-- Dependencies -->
|
<!-- Dependencies -->
|
||||||
<okio.version>1.0.1</okio.version>
|
<okio.version>1.0.2-SNAPSHOT</okio.version>
|
||||||
|
|
||||||
<!-- Test Dependencies -->
|
<!-- Test Dependencies -->
|
||||||
<junit.version>4.11</junit.version>
|
<junit.version>4.11</junit.version>
|
||||||
@@ -58,6 +58,11 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>${junit.version}</version>
|
<version>${junit.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okio</groupId>
|
||||||
|
<artifactId>okio</artifactId>
|
||||||
|
<version>${okio.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user