source: main/trunk/model-sites-dev/cambridge-museum/collect/waikato-independent/pre-import/EditableDatabaseTable/src/org/json/JSONTokener.java@ 34493

Last change on this file since 34493 was 34493, checked in by davidb, 4 years ago

Base project for providing jquery/jquery-ui controlled interface to editing a database table

File size: 12.4 KB
Line 
1package org.json;
2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStream;
6import java.io.InputStreamReader;
7import java.io.Reader;
8import java.io.StringReader;
9
10/*
11Copyright (c) 2002 JSON.org
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in all
21copies or substantial portions of the Software.
22
23The Software shall be used for Good, not Evil.
24
25THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31SOFTWARE.
32*/
33
34/**
35 * A JSONTokener takes a source string and extracts characters and tokens from
36 * it. It is used by the JSONObject and JSONArray constructors to parse
37 * JSON source strings.
38 * @author JSON.org
39 * @version 2010-12-24
40 */
41public class JSONTokener {
42
43 private int character;
44 private boolean eof;
45 private int index;
46 private int line;
47 private char previous;
48 private Reader reader;
49 private boolean usePrevious;
50
51
52 /**
53 * Construct a JSONTokener from a Reader.
54 *
55 * @param reader A reader.
56 */
57 public JSONTokener(Reader reader) {
58 this.reader = reader.markSupported() ?
59 reader : new BufferedReader(reader);
60 this.eof = false;
61 this.usePrevious = false;
62 this.previous = 0;
63 this.index = 0;
64 this.character = 1;
65 this.line = 1;
66 }
67
68
69 /**
70 * Construct a JSONTokener from an InputStream.
71 */
72 public JSONTokener(InputStream inputStream) throws JSONException {
73 this(new InputStreamReader(inputStream));
74 }
75
76
77 /**
78 * Construct a JSONTokener from a string.
79 *
80 * @param s A source string.
81 */
82 public JSONTokener(String s) {
83 this(new StringReader(s));
84 }
85
86
87 /**
88 * Back up one character. This provides a sort of lookahead capability,
89 * so that you can test for a digit or letter before attempting to parse
90 * the next number or identifier.
91 */
92 public void back() throws JSONException {
93 if (usePrevious || index <= 0) {
94 throw new JSONException("Stepping back two steps is not supported");
95 }
96 this.index -= 1;
97 this.character -= 1;
98 this.usePrevious = true;
99 this.eof = false;
100 }
101
102
103 /**
104 * Get the hex value of a character (base16).
105 * @param c A character between '0' and '9' or between 'A' and 'F' or
106 * between 'a' and 'f'.
107 * @return An int between 0 and 15, or -1 if c was not a hex digit.
108 */
109 public static int dehexchar(char c) {
110 if (c >= '0' && c <= '9') {
111 return c - '0';
112 }
113 if (c >= 'A' && c <= 'F') {
114 return c - ('A' - 10);
115 }
116 if (c >= 'a' && c <= 'f') {
117 return c - ('a' - 10);
118 }
119 return -1;
120 }
121
122 public boolean end() {
123 return eof && !usePrevious;
124 }
125
126
127 /**
128 * Determine if the source string still contains characters that next()
129 * can consume.
130 * @return true if not yet at the end of the source.
131 */
132 public boolean more() throws JSONException {
133 next();
134 if (end()) {
135 return false;
136 }
137 back();
138 return true;
139 }
140
141
142 /**
143 * Get the next character in the source string.
144 *
145 * @return The next character, or 0 if past the end of the source string.
146 */
147 public char next() throws JSONException {
148 int c;
149 if (this.usePrevious) {
150 this.usePrevious = false;
151 c = this.previous;
152 } else {
153 try {
154 c = this.reader.read();
155 } catch (IOException exception) {
156 throw new JSONException(exception);
157 }
158
159 if (c <= 0) { // End of stream
160 this.eof = true;
161 c = 0;
162 }
163 }
164 this.index += 1;
165 if (this.previous == '\r') {
166 this.line += 1;
167 this.character = c == '\n' ? 0 : 1;
168 } else if (c == '\n') {
169 this.line += 1;
170 this.character = 0;
171 } else {
172 this.character += 1;
173 }
174 this.previous = (char) c;
175 return this.previous;
176 }
177
178
179 /**
180 * Consume the next character, and check that it matches a specified
181 * character.
182 * @param c The character to match.
183 * @return The character.
184 * @throws JSONException if the character does not match.
185 */
186 public char next(char c) throws JSONException {
187 char n = next();
188 if (n != c) {
189 throw syntaxError("Expected '" + c + "' and instead saw '" +
190 n + "'");
191 }
192 return n;
193 }
194
195
196 /**
197 * Get the next n characters.
198 *
199 * @param n The number of characters to take.
200 * @return A string of n characters.
201 * @throws JSONException
202 * Substring bounds error if there are not
203 * n characters remaining in the source string.
204 */
205 public String next(int n) throws JSONException {
206 if (n == 0) {
207 return "";
208 }
209
210 char[] chars = new char[n];
211 int pos = 0;
212
213 while (pos < n) {
214 chars[pos] = next();
215 if (end()) {
216 throw syntaxError("Substring bounds error");
217 }
218 pos += 1;
219 }
220 return new String(chars);
221 }
222
223
224 /**
225 * Get the next char in the string, skipping whitespace.
226 * @throws JSONException
227 * @return A character, or 0 if there are no more characters.
228 */
229 public char nextClean() throws JSONException {
230 for (;;) {
231 char c = next();
232 if (c == 0 || c > ' ') {
233 return c;
234 }
235 }
236 }
237
238
239 /**
240 * Return the characters up to the next close quote character.
241 * Backslash processing is done. The formal JSON format does not
242 * allow strings in single quotes, but an implementation is allowed to
243 * accept them.
244 * @param quote The quoting character, either
245 * <code>"</code>&nbsp;<small>(double quote)</small> or
246 * <code>'</code>&nbsp;<small>(single quote)</small>.
247 * @return A String.
248 * @throws JSONException Unterminated string.
249 */
250 public String nextString(char quote) throws JSONException {
251 char c;
252 StringBuffer sb = new StringBuffer();
253 for (;;) {
254 c = next();
255 switch (c) {
256 case 0:
257 case '\n':
258 case '\r':
259 throw syntaxError("Unterminated string");
260 case '\\':
261 c = next();
262 switch (c) {
263 case 'b':
264 sb.append('\b');
265 break;
266 case 't':
267 sb.append('\t');
268 break;
269 case 'n':
270 sb.append('\n');
271 break;
272 case 'f':
273 sb.append('\f');
274 break;
275 case 'r':
276 sb.append('\r');
277 break;
278 case 'u':
279 sb.append((char)Integer.parseInt(next(4), 16));
280 break;
281 case '"':
282 case '\'':
283 case '\\':
284 case '/':
285 sb.append(c);
286 break;
287 default:
288 throw syntaxError("Illegal escape.");
289 }
290 break;
291 default:
292 if (c == quote) {
293 return sb.toString();
294 }
295 sb.append(c);
296 }
297 }
298 }
299
300
301 /**
302 * Get the text up but not including the specified character or the
303 * end of line, whichever comes first.
304 * @param delimiter A delimiter character.
305 * @return A string.
306 */
307 public String nextTo(char delimiter) throws JSONException {
308 StringBuffer sb = new StringBuffer();
309 for (;;) {
310 char c = next();
311 if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
312 if (c != 0) {
313 back();
314 }
315 return sb.toString().trim();
316 }
317 sb.append(c);
318 }
319 }
320
321
322 /**
323 * Get the text up but not including one of the specified delimiter
324 * characters or the end of line, whichever comes first.
325 * @param delimiters A set of delimiter characters.
326 * @return A string, trimmed.
327 */
328 public String nextTo(String delimiters) throws JSONException {
329 char c;
330 StringBuffer sb = new StringBuffer();
331 for (;;) {
332 c = next();
333 if (delimiters.indexOf(c) >= 0 || c == 0 ||
334 c == '\n' || c == '\r') {
335 if (c != 0) {
336 back();
337 }
338 return sb.toString().trim();
339 }
340 sb.append(c);
341 }
342 }
343
344
345 /**
346 * Get the next value. The value can be a Boolean, Double, Integer,
347 * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
348 * @throws JSONException If syntax error.
349 *
350 * @return An object.
351 */
352 public Object nextValue() throws JSONException {
353 char c = nextClean();
354 String string;
355
356 switch (c) {
357 case '"':
358 case '\'':
359 return nextString(c);
360 case '{':
361 back();
362 return new JSONObject(this);
363 case '[':
364 back();
365 return new JSONArray(this);
366 }
367
368 /*
369 * Handle unquoted text. This could be the values true, false, or
370 * null, or it can be a number. An implementation (such as this one)
371 * is allowed to also accept non-standard forms.
372 *
373 * Accumulate characters until we reach the end of the text or a
374 * formatting character.
375 */
376
377 StringBuffer sb = new StringBuffer();
378 while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
379 sb.append(c);
380 c = next();
381 }
382 back();
383
384 string = sb.toString().trim();
385 if (string.equals("")) {
386 throw syntaxError("Missing value");
387 }
388 return JSONObject.stringToValue(string);
389 }
390
391
392 /**
393 * Skip characters until the next character is the requested character.
394 * If the requested character is not found, no characters are skipped.
395 * @param to A character to skip to.
396 * @return The requested character, or zero if the requested character
397 * is not found.
398 */
399 public char skipTo(char to) throws JSONException {
400 char c;
401 try {
402 int startIndex = this.index;
403 int startCharacter = this.character;
404 int startLine = this.line;
405 reader.mark(Integer.MAX_VALUE);
406 do {
407 c = next();
408 if (c == 0) {
409 reader.reset();
410 this.index = startIndex;
411 this.character = startCharacter;
412 this.line = startLine;
413 return c;
414 }
415 } while (c != to);
416 } catch (IOException exc) {
417 throw new JSONException(exc);
418 }
419
420 back();
421 return c;
422 }
423
424
425 /**
426 * Make a JSONException to signal a syntax error.
427 *
428 * @param message The error message.
429 * @return A JSONException object, suitable for throwing
430 */
431 public JSONException syntaxError(String message) {
432 return new JSONException(message + toString());
433 }
434
435
436 /**
437 * Make a printable string of this JSONTokener.
438 *
439 * @return " at {index} [character {character} line {line}]"
440 */
441 public String toString() {
442 return " at " + index + " [character " + this.character + " line " +
443 this.line + "]";
444 }
445}
Note: See TracBrowser for help on using the repository browser.