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