|
|
|
@ -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"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|