Skip to content

Commit 359b43d

Browse files
committed
Apply corner-case fixes under instruction
1 parent bcbbc89 commit 359b43d

5 files changed

Lines changed: 98 additions & 18 deletions

File tree

src/main/java/org/json/JSONArray.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public JSONArray() {
8080
* @param x
8181
* A JSONTokener
8282
* @throws JSONException
83-
* If there is a syntax error.
83+
* If there is a syntax error.
8484
*/
8585
public JSONArray(JSONTokener x) throws JSONException {
8686
this(x, x.getJsonParserConfiguration());
@@ -103,10 +103,10 @@ public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration)
103103
*
104104
* @param x A JSONTokener instance from which the JSONArray is constructed.
105105
* @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser.
106-
* @param eofRequired A boolean that determines whether this array is the root.
106+
* @param isInitial A boolean that determines whether this array is the root.
107107
* @throws JSONException If a syntax error occurs during the construction of the JSONArray.
108108
*/
109-
JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean eofRequired) throws JSONException {
109+
JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) throws JSONException {
110110
this();
111111

112112
if (x.nextClean() != '[') {
@@ -130,10 +130,10 @@ public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration)
130130
x.back();
131131
this.myArrayList.add(x.nextValue());
132132
}
133-
if (checkForSyntaxError(x, jsonParserConfiguration, eofRequired)) return;
133+
if (checkForSyntaxError(x, jsonParserConfiguration, isInitial)) return;
134134
}
135135
} else {
136-
if (eofRequired && jsonParserConfiguration.isStrictMode() && x.nextClean() != 0) {
136+
if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != 0) {
137137
throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text");
138138
}
139139
}

src/main/java/org/json/JSONObject.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ public JSONObject(JSONObject jo, String ... names) {
195195
* @param x
196196
* A JSONTokener object containing the source string.
197197
* @throws JSONException
198-
* If there is a syntax error in the source string or a
199-
* duplicated key.
198+
* If there is a syntax error in the source string or a
199+
* duplicated key.
200200
*/
201201
public JSONObject(JSONTokener x) throws JSONException {
202202
this(x, x.getJsonParserConfiguration());
@@ -210,8 +210,8 @@ public JSONObject(JSONTokener x) throws JSONException {
210210
* @param jsonParserConfiguration
211211
* Variable to pass parser custom configuration for json parsing.
212212
* @throws JSONException
213-
* If there is a syntax error in the source string or a
214-
* duplicated key.
213+
* If there is a syntax error in the source string or a
214+
* duplicated key.
215215
*/
216216
public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
217217
this(x, jsonParserConfiguration, x.isAtStart());
@@ -225,20 +225,20 @@ public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration
225225
* A JSONTokener object containing the source string.
226226
* @param jsonParserConfiguration
227227
* Variable to pass parser custom configuration for json parsing.
228-
* @param eofRequired
228+
* @param isInitial
229229
* A boolean that determines whether this object is the root.
230230
* @throws JSONException
231-
* If there is a syntax error in the source string or a
232-
* duplicated key.
231+
* If there is a syntax error in the source string or a
232+
* duplicated key.
233233
*/
234-
JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean eofRequired) throws JSONException {
234+
JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) throws JSONException {
235235
this();
236236

237237
if (x.nextClean() != '{') {
238238
throw x.syntaxError("A JSONObject text must begin with '{'");
239239
}
240240
for (;;) {
241-
if (parseJSONObject(x, jsonParserConfiguration, eofRequired)) {
241+
if (parseJSONObject(x, jsonParserConfiguration, isInitial)) {
242242
return;
243243
}
244244
}

src/main/java/org/json/JSONTokener.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public class JSONTokener {
3131
private boolean usePrevious;
3232
/** the number of characters read in the previous line. */
3333
private long characterPreviousLine;
34+
/** number of non-whitespace characters read from the source. */
35+
private long contentCharCount;
3436

3537
// access to this object is required for strict mode checking
3638
private JSONParserConfiguration jsonParserConfiguration;
@@ -60,6 +62,7 @@ public JSONTokener(Reader reader, JSONParserConfiguration jsonParserConfiguratio
6062
this.usePrevious = false;
6163
this.previous = 0;
6264
this.index = 0;
65+
this.contentCharCount = 0;
6366
this.character = 1;
6467
this.characterPreviousLine = 0;
6568
this.line = 1;
@@ -121,12 +124,14 @@ public void setJsonParserConfiguration(JSONParserConfiguration jsonParserConfigu
121124
}
122125

123126
/**
124-
* Returns whether the tokener is currently positioned at the beginning,
127+
* Returns whether the tokener is positioned at the beginning,
128+
* i.e. only whitespace characters (or no characters at all) have been read so far.
129+
* Consuming and backing up over the first characters does not change the result.
125130
*
126-
* @return true if the current input position is the beginning
131+
* @return true if no non-whitespace character has been read
127132
*/
128-
public boolean isAtStart() {
129-
return this.index == 0;
133+
protected boolean isAtStart() {
134+
return this.contentCharCount == 0;
130135
}
131136

132137
/**
@@ -140,6 +145,9 @@ public void back() throws JSONException {
140145
if (this.usePrevious || this.index <= 0) {
141146
throw new JSONException("Stepping back two steps is not supported");
142147
}
148+
if (this.previous > ' ') {
149+
this.contentCharCount--;
150+
}
143151
this.decrementIndexes();
144152
this.usePrevious = true;
145153
this.eof = false;
@@ -240,6 +248,9 @@ public char next() throws JSONException {
240248
return 0;
241249
}
242250
this.incrementIndexes(c);
251+
if (c > ' ') {
252+
this.contentCharCount++;
253+
}
243254
this.previous = (char) c;
244255
return this.previous;
245256
}
@@ -558,6 +569,7 @@ public char skipTo(char to) throws JSONException {
558569
long startIndex = this.index;
559570
long startCharacter = this.character;
560571
long startLine = this.line;
572+
long startContentCharCount = this.contentCharCount;
561573
this.reader.mark(1000000);
562574
do {
563575
c = this.next();
@@ -569,6 +581,7 @@ public char skipTo(char to) throws JSONException {
569581
this.index = startIndex;
570582
this.character = startCharacter;
571583
this.line = startLine;
584+
this.contentCharCount = startContentCharCount;
572585
return 0;
573586
}
574587
} while (c != to);

src/test/java/org/json/junit/JSONArrayTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,7 +1573,24 @@ public void strictModeShouldCheckTrailingCharactersAfterNextAndBack() {
15731573
new JSONParserConfiguration().withStrictMode();
15741574

15751575
JSONTokener tok = new JSONTokener("[]xxx");
1576+
tok.next();
1577+
tok.back();
1578+
1579+
JSONException exception = assertThrows(
1580+
JSONException.class,
1581+
() -> new JSONArray(tok, strict));
15761582

1583+
assertTrue(exception.getMessage().contains(
1584+
"Unparsed characters found at end of input text"));
1585+
}
1586+
1587+
@Test
1588+
public void strictModeShouldCheckTrailingCharactersAfterConsumedWhitespace() {
1589+
JSONParserConfiguration strict =
1590+
new JSONParserConfiguration().withStrictMode();
1591+
1592+
JSONTokener tok = new JSONTokener(" []xxx");
1593+
tok.next();
15771594
tok.next();
15781595
tok.back();
15791596

@@ -1584,4 +1601,21 @@ public void strictModeShouldCheckTrailingCharactersAfterNextAndBack() {
15841601
assertTrue(exception.getMessage().contains(
15851602
"Unparsed characters found at end of input text"));
15861603
}
1604+
1605+
@Test
1606+
public void strictModeShouldCheckTrailingCharactersAfterNextCleanAndBack() {
1607+
JSONParserConfiguration strict =
1608+
new JSONParserConfiguration().withStrictMode();
1609+
1610+
JSONTokener tok = new JSONTokener(" []xxx");
1611+
tok.nextClean();
1612+
tok.back();
1613+
1614+
JSONException exception = assertThrows(
1615+
JSONException.class,
1616+
() -> new JSONArray(tok, strict));
1617+
1618+
assertTrue(exception.getMessage().contains(
1619+
"Unparsed characters found at end of input text"));
1620+
}
15871621
}

src/test/java/org/json/junit/JSONObjectTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4343,7 +4343,24 @@ public void strictModeShouldCheckTrailingCharactersAfterNextAndBack() {
43434343
new JSONParserConfiguration().withStrictMode();
43444344

43454345
JSONTokener tok = new JSONTokener("{}xxx");
4346+
tok.next();
4347+
tok.back();
4348+
4349+
JSONException exception = assertThrows(
4350+
JSONException.class,
4351+
() -> new JSONObject(tok, strict));
4352+
4353+
assertTrue(exception.getMessage().contains(
4354+
"Unparsed characters found at end of input text"));
4355+
}
4356+
4357+
@Test
4358+
public void strictModeShouldCheckTrailingCharactersAfterConsumedWhitespace() {
4359+
JSONParserConfiguration strict =
4360+
new JSONParserConfiguration().withStrictMode();
43464361

4362+
JSONTokener tok = new JSONTokener(" {}xxx");
4363+
tok.next();
43474364
tok.next();
43484365
tok.back();
43494366

@@ -4355,4 +4372,20 @@ public void strictModeShouldCheckTrailingCharactersAfterNextAndBack() {
43554372
"Unparsed characters found at end of input text"));
43564373
}
43574374

4375+
@Test
4376+
public void strictModeShouldCheckTrailingCharactersAfterNextCleanAndBack() {
4377+
JSONParserConfiguration strict =
4378+
new JSONParserConfiguration().withStrictMode();
4379+
4380+
JSONTokener tok = new JSONTokener(" {}xxx");
4381+
tok.nextClean();
4382+
tok.back();
4383+
4384+
JSONException exception = assertThrows(
4385+
JSONException.class,
4386+
() -> new JSONObject(tok, strict));
4387+
4388+
assertTrue(exception.getMessage().contains(
4389+
"Unparsed characters found at end of input text"));
4390+
}
43584391
}

0 commit comments

Comments
 (0)