|
|
@ -91,22 +91,22 @@ public class JSONTokener {
|
|
|
|
public Object nextValue() throws JSONException {
|
|
|
|
public Object nextValue() throws JSONException {
|
|
|
|
int c = nextCleanInternal();
|
|
|
|
int c = nextCleanInternal();
|
|
|
|
switch (c) {
|
|
|
|
switch (c) {
|
|
|
|
case -1:
|
|
|
|
case -1:
|
|
|
|
throw syntaxError("End of input");
|
|
|
|
throw syntaxError("End of input");
|
|
|
|
|
|
|
|
|
|
|
|
case '{':
|
|
|
|
case '{':
|
|
|
|
return readObject();
|
|
|
|
return readObject();
|
|
|
|
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
case '[':
|
|
|
|
return readArray();
|
|
|
|
return readArray();
|
|
|
|
|
|
|
|
|
|
|
|
case '\'':
|
|
|
|
case '\'':
|
|
|
|
case '"':
|
|
|
|
case '"':
|
|
|
|
return nextString((char) c);
|
|
|
|
return nextString((char) c);
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
this.pos--;
|
|
|
|
this.pos--;
|
|
|
|
return readLiteral();
|
|
|
|
return readLiteral();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -114,50 +114,50 @@ public class JSONTokener {
|
|
|
|
while (this.pos < this.in.length()) {
|
|
|
|
while (this.pos < this.in.length()) {
|
|
|
|
int c = this.in.charAt(this.pos++);
|
|
|
|
int c = this.in.charAt(this.pos++);
|
|
|
|
switch (c) {
|
|
|
|
switch (c) {
|
|
|
|
case '\t':
|
|
|
|
case '\t':
|
|
|
|
case ' ':
|
|
|
|
case ' ':
|
|
|
|
case '\n':
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
case '\r':
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
case '/':
|
|
|
|
case '/':
|
|
|
|
if (this.pos == this.in.length()) {
|
|
|
|
if (this.pos == this.in.length()) {
|
|
|
|
return c;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char peek = this.in.charAt(this.pos);
|
|
|
|
char peek = this.in.charAt(this.pos);
|
|
|
|
switch (peek) {
|
|
|
|
switch (peek) {
|
|
|
|
case '*':
|
|
|
|
case '*':
|
|
|
|
// skip a /* c-style comment */
|
|
|
|
// skip a /* c-style comment */
|
|
|
|
this.pos++;
|
|
|
|
this.pos++;
|
|
|
|
int commentEnd = this.in.indexOf("*/", this.pos);
|
|
|
|
int commentEnd = this.in.indexOf("*/", this.pos);
|
|
|
|
if (commentEnd == -1) {
|
|
|
|
if (commentEnd == -1) {
|
|
|
|
throw syntaxError("Unterminated comment");
|
|
|
|
throw syntaxError("Unterminated comment");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
this.pos = commentEnd + 2;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case '/':
|
|
|
|
|
|
|
|
// skip a // end-of-line comment
|
|
|
|
|
|
|
|
this.pos++;
|
|
|
|
|
|
|
|
skipToEndOfLine();
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.pos = commentEnd + 2;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case '/':
|
|
|
|
case '#':
|
|
|
|
// skip a // end-of-line comment
|
|
|
|
/*
|
|
|
|
this.pos++;
|
|
|
|
* Skip a # hash end-of-line comment. The JSON RFC doesn't specify
|
|
|
|
|
|
|
|
* this behavior, but it's required to parse existing documents. See
|
|
|
|
|
|
|
|
* https://b/2571423.
|
|
|
|
|
|
|
|
*/
|
|
|
|
skipToEndOfLine();
|
|
|
|
skipToEndOfLine();
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
return c;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case '#':
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Skip a # hash end-of-line comment. The JSON RFC doesn't specify this
|
|
|
|
|
|
|
|
* behavior, but it's required to parse existing documents. See
|
|
|
|
|
|
|
|
* https://b/2571423.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
skipToEndOfLine();
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return c;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -239,34 +239,34 @@ public class JSONTokener {
|
|
|
|
private char readEscapeCharacter() throws JSONException {
|
|
|
|
private char readEscapeCharacter() throws JSONException {
|
|
|
|
char escaped = this.in.charAt(this.pos++);
|
|
|
|
char escaped = this.in.charAt(this.pos++);
|
|
|
|
switch (escaped) {
|
|
|
|
switch (escaped) {
|
|
|
|
case 'u':
|
|
|
|
case 'u':
|
|
|
|
if (this.pos + 4 > this.in.length()) {
|
|
|
|
if (this.pos + 4 > this.in.length()) {
|
|
|
|
throw syntaxError("Unterminated escape sequence");
|
|
|
|
throw syntaxError("Unterminated escape sequence");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
String hex = this.in.substring(this.pos, this.pos + 4);
|
|
|
|
String hex = this.in.substring(this.pos, this.pos + 4);
|
|
|
|
this.pos += 4;
|
|
|
|
this.pos += 4;
|
|
|
|
return (char) Integer.parseInt(hex, 16);
|
|
|
|
return (char) Integer.parseInt(hex, 16);
|
|
|
|
|
|
|
|
|
|
|
|
case 't':
|
|
|
|
case 't':
|
|
|
|
return '\t';
|
|
|
|
return '\t';
|
|
|
|
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
case 'b':
|
|
|
|
return '\b';
|
|
|
|
return '\b';
|
|
|
|
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
case 'n':
|
|
|
|
return '\n';
|
|
|
|
return '\n';
|
|
|
|
|
|
|
|
|
|
|
|
case 'r':
|
|
|
|
case 'r':
|
|
|
|
return '\r';
|
|
|
|
return '\r';
|
|
|
|
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
case 'f':
|
|
|
|
return '\f';
|
|
|
|
return '\f';
|
|
|
|
|
|
|
|
|
|
|
|
case '\'':
|
|
|
|
case '\'':
|
|
|
|
case '"':
|
|
|
|
case '"':
|
|
|
|
case '\\':
|
|
|
|
case '\\':
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
return escaped;
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -396,13 +396,13 @@ public class JSONTokener {
|
|
|
|
result.put((String) name, nextValue());
|
|
|
|
result.put((String) name, nextValue());
|
|
|
|
|
|
|
|
|
|
|
|
switch (nextCleanInternal()) {
|
|
|
|
switch (nextCleanInternal()) {
|
|
|
|
case '}':
|
|
|
|
case '}':
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
case ';':
|
|
|
|
case ';':
|
|
|
|
case ',':
|
|
|
|
case ',':
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
throw syntaxError("Unterminated object");
|
|
|
|
throw syntaxError("Unterminated object");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -422,34 +422,34 @@ public class JSONTokener {
|
|
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
while (true) {
|
|
|
|
switch (nextCleanInternal()) {
|
|
|
|
switch (nextCleanInternal()) {
|
|
|
|
case -1:
|
|
|
|
case -1:
|
|
|
|
throw syntaxError("Unterminated array");
|
|
|
|
throw syntaxError("Unterminated array");
|
|
|
|
case ']':
|
|
|
|
case ']':
|
|
|
|
if (hasTrailingSeparator) {
|
|
|
|
if (hasTrailingSeparator) {
|
|
|
|
|
|
|
|
result.put(null);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
case ',':
|
|
|
|
|
|
|
|
case ';':
|
|
|
|
|
|
|
|
/* A separator without a value first means "null". */
|
|
|
|
result.put(null);
|
|
|
|
result.put(null);
|
|
|
|
}
|
|
|
|
hasTrailingSeparator = true;
|
|
|
|
return result;
|
|
|
|
continue;
|
|
|
|
case ',':
|
|
|
|
default:
|
|
|
|
case ';':
|
|
|
|
this.pos--;
|
|
|
|
/* A separator without a value first means "null". */
|
|
|
|
|
|
|
|
result.put(null);
|
|
|
|
|
|
|
|
hasTrailingSeparator = true;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
this.pos--;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result.put(nextValue());
|
|
|
|
result.put(nextValue());
|
|
|
|
|
|
|
|
|
|
|
|
switch (nextCleanInternal()) {
|
|
|
|
switch (nextCleanInternal()) {
|
|
|
|
case ']':
|
|
|
|
case ']':
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
case ',':
|
|
|
|
case ',':
|
|
|
|
case ';':
|
|
|
|
case ';':
|
|
|
|
hasTrailingSeparator = true;
|
|
|
|
hasTrailingSeparator = true;
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
throw syntaxError("Unterminated array");
|
|
|
|
throw syntaxError("Unterminated array");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|