Skip to content

Commit 5024f2d

Browse files
authored
Merge pull request #352 from johnjaylward/ErrorMessagePositionFixes
Error message position fixes
2 parents 1add124 + 16baa32 commit 5024f2d

File tree

3 files changed

+117
-65
lines changed

3 files changed

+117
-65
lines changed

CDL.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ of this software and associated documentation files (the "Software"), to deal
2222
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2323
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2424
SOFTWARE.
25-
*/
25+
*/
2626

2727
/**
2828
* This provides static methods to convert comma delimited text into a
@@ -70,9 +70,12 @@ private static String getValue(JSONTokener x) throws JSONException {
7070
c = x.next();
7171
if (c == q) {
7272
//Handle escaped double-quote
73-
if(x.next() != '\"')
74-
{
75-
x.back();
73+
char nextC = x.next();
74+
if(nextC != '\"') {
75+
// if our quote was the end of the file, don't step
76+
if(nextC > 0) {
77+
x.back();
78+
}
7679
break;
7780
}
7881
}

JSONTokener.java

Lines changed: 104 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ of this software and associated documentation files (the "Software"), to deal
2929
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3030
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3131
SOFTWARE.
32-
*/
32+
*/
3333

3434
/**
3535
* A JSONTokener takes a source string and extracts characters and tokens from
@@ -39,42 +39,45 @@ of this software and associated documentation files (the "Software"), to deal
3939
* @version 2014-05-03
4040
*/
4141
public class JSONTokener {
42-
/** current read character. */
42+
/** current read character position on the current line. */
4343
private long character;
4444
/** flag to indicate if the end of the input has been found. */
4545
private boolean eof;
4646
/** current read index of the input. */
4747
private long index;
4848
/** current line of the input. */
4949
private long line;
50-
/** previous index of the input. */
50+
/** previous character read from the input. */
5151
private char previous;
5252
/** Reader for the input. */
5353
private final Reader reader;
5454
/** flag to indicate that a previous character was requested. */
5555
private boolean usePrevious;
56+
/** the number of characters read in the previous line. */
57+
private long characterPreviousLine;
5658

5759

5860
/**
59-
* Construct a JSONTokener from a Reader.
61+
* Construct a JSONTokener from a Reader. The caller must close the Reader.
6062
*
6163
* @param reader A reader.
6264
*/
6365
public JSONTokener(Reader reader) {
6466
this.reader = reader.markSupported()
65-
? reader
66-
: new BufferedReader(reader);
67+
? reader
68+
: new BufferedReader(reader);
6769
this.eof = false;
6870
this.usePrevious = false;
6971
this.previous = 0;
7072
this.index = 0;
7173
this.character = 1;
74+
this.characterPreviousLine = 0;
7275
this.line = 1;
7376
}
7477

7578

7679
/**
77-
* Construct a JSONTokener from an InputStream.
80+
* Construct a JSONTokener from an InputStream. The caller must close the input stream.
7881
* @param inputStream The source.
7982
*/
8083
public JSONTokener(InputStream inputStream) {
@@ -103,12 +106,23 @@ public void back() throws JSONException {
103106
if (this.usePrevious || this.index <= 0) {
104107
throw new JSONException("Stepping back two steps is not supported");
105108
}
106-
this.index -= 1;
107-
this.character -= 1;
109+
this.decrementIndexes();
108110
this.usePrevious = true;
109111
this.eof = false;
110112
}
111113

114+
/**
115+
* Decrements the indexes for the {@link #back()} method based on the previous character read.
116+
*/
117+
private void decrementIndexes() {
118+
this.index--;
119+
if(this.previous=='\r' || this.previous == '\n') {
120+
this.line--;
121+
this.character=this.characterPreviousLine ;
122+
} else if(this.character > 0){
123+
this.character--;
124+
}
125+
}
112126

113127
/**
114128
* Get the hex value of a character (base16).
@@ -130,6 +144,8 @@ public static int dehexchar(char c) {
130144
}
131145

132146
/**
147+
* Checks if the end of the input has been reached.
148+
*
133149
* @return true if at the end of the file and we didn't step back
134150
*/
135151
public boolean end() {
@@ -145,11 +161,24 @@ public boolean end() {
145161
* or backward while checking for more data.
146162
*/
147163
public boolean more() throws JSONException {
148-
this.next();
149-
if (this.end()) {
150-
return false;
164+
if(this.usePrevious) {
165+
return true;
166+
}
167+
try {
168+
this.reader.mark(1);
169+
} catch (IOException e) {
170+
throw new JSONException("Unable to preserve stream position", e);
171+
}
172+
try {
173+
// -1 is EOF, but next() can not consume the null character '\0'
174+
if(this.reader.read() <= 0) {
175+
this.eof = true;
176+
return false;
177+
}
178+
this.reader.reset();
179+
} catch (IOException e) {
180+
throw new JSONException("Unable to read the next character from the stream", e);
151181
}
152-
this.back();
153182
return true;
154183
}
155184

@@ -171,26 +200,39 @@ public char next() throws JSONException {
171200
} catch (IOException exception) {
172201
throw new JSONException(exception);
173202
}
174-
175-
if (c <= 0) { // End of stream
176-
this.eof = true;
177-
c = 0;
178-
}
179203
}
180-
this.index += 1;
181-
if (this.previous == '\r') {
182-
this.line += 1;
183-
this.character = c == '\n' ? 0 : 1;
184-
} else if (c == '\n') {
185-
this.line += 1;
186-
this.character = 0;
187-
} else {
188-
this.character += 1;
204+
if (c <= 0) { // End of stream
205+
this.eof = true;
206+
return 0;
189207
}
208+
this.incrementIndexes(c);
190209
this.previous = (char) c;
191210
return this.previous;
192211
}
193212

213+
/**
214+
* Increments the internal indexes according to the previous character
215+
* read and the character passed as the current character.
216+
* @param c the current character read.
217+
*/
218+
private void incrementIndexes(int c) {
219+
if(c > 0) {
220+
this.index++;
221+
if(c=='\r') {
222+
this.line++;
223+
this.characterPreviousLine = this.character;
224+
this.character=0;
225+
}else if (c=='\n') {
226+
if(this.previous != '\r') {
227+
this.line++;
228+
this.characterPreviousLine = this.character;
229+
}
230+
this.character=0;
231+
} else {
232+
this.character++;
233+
}
234+
}
235+
}
194236

195237
/**
196238
* Consume the next character, and check that it matches a specified
@@ -202,8 +244,11 @@ public char next() throws JSONException {
202244
public char next(char c) throws JSONException {
203245
char n = this.next();
204246
if (n != c) {
205-
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
206-
n + "'");
247+
if(n > 0) {
248+
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
249+
n + "'");
250+
}
251+
throw this.syntaxError("Expected '" + c + "' and instead saw ''");
207252
}
208253
return n;
209254
}
@@ -218,23 +263,23 @@ public char next(char c) throws JSONException {
218263
* Substring bounds error if there are not
219264
* n characters remaining in the source string.
220265
*/
221-
public String next(int n) throws JSONException {
222-
if (n == 0) {
223-
return "";
224-
}
266+
public String next(int n) throws JSONException {
267+
if (n == 0) {
268+
return "";
269+
}
225270

226-
char[] chars = new char[n];
227-
int pos = 0;
271+
char[] chars = new char[n];
272+
int pos = 0;
228273

229-
while (pos < n) {
230-
chars[pos] = this.next();
231-
if (this.end()) {
232-
throw this.syntaxError("Substring bounds error");
233-
}
234-
pos += 1;
235-
}
236-
return new String(chars);
237-
}
274+
while (pos < n) {
275+
chars[pos] = this.next();
276+
if (this.end()) {
277+
throw this.syntaxError("Substring bounds error");
278+
}
279+
pos += 1;
280+
}
281+
return new String(chars);
282+
}
238283

239284

240285
/**
@@ -378,15 +423,15 @@ public Object nextValue() throws JSONException {
378423
String string;
379424

380425
switch (c) {
381-
case '"':
382-
case '\'':
383-
return this.nextString(c);
384-
case '{':
385-
this.back();
386-
return new JSONObject(this);
387-
case '[':
388-
this.back();
389-
return new JSONArray(this);
426+
case '"':
427+
case '\'':
428+
return this.nextString(c);
429+
case '{':
430+
this.back();
431+
return new JSONObject(this);
432+
case '[':
433+
this.back();
434+
return new JSONArray(this);
390435
}
391436

392437
/*
@@ -432,21 +477,24 @@ public char skipTo(char to) throws JSONException {
432477
do {
433478
c = this.next();
434479
if (c == 0) {
480+
// in some readers, reset() may throw an exception if
481+
// the remaining portion of the input is greater than
482+
// the mark size (1,000,000 above).
435483
this.reader.reset();
436484
this.index = startIndex;
437485
this.character = startCharacter;
438486
this.line = startLine;
439-
return c;
487+
return 0;
440488
}
441489
} while (c != to);
490+
this.reader.mark(1);
442491
} catch (IOException exception) {
443492
throw new JSONException(exception);
444493
}
445494
this.back();
446495
return c;
447496
}
448497

449-
450498
/**
451499
* Make a JSONException to signal a syntax error.
452500
*
@@ -476,6 +524,6 @@ public JSONException syntaxError(String message, Throwable causedBy) {
476524
@Override
477525
public String toString() {
478526
return " at " + this.index + " [character " + this.character + " line " +
479-
this.line + "]";
527+
this.line + "]";
480528
}
481529
}

XMLTokener.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,8 @@ public String nextCDATA() throws JSONException {
6464
char c;
6565
int i;
6666
StringBuilder sb = new StringBuilder();
67-
for (;;) {
67+
while (more()) {
6868
c = next();
69-
if (end()) {
70-
throw syntaxError("Unclosed CDATA");
71-
}
7269
sb.append(c);
7370
i = sb.length() - 3;
7471
if (i >= 0 && sb.charAt(i) == ']' &&
@@ -77,6 +74,7 @@ public String nextCDATA() throws JSONException {
7774
return sb.toString();
7875
}
7976
}
77+
throw syntaxError("Unclosed CDATA");
8078
}
8179

8280

@@ -103,7 +101,10 @@ public Object nextContent() throws JSONException {
103101
}
104102
sb = new StringBuilder();
105103
for (;;) {
106-
if (c == '<' || c == 0) {
104+
if (c == 0) {
105+
return sb.toString().trim();
106+
}
107+
if (c == '<') {
107108
back();
108109
return sb.toString().trim();
109110
}

0 commit comments

Comments
 (0)