1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package com.google.gson.stream;
18
19 import com.google.gson.internal.JsonReaderInternalAccess;
20 import com.google.gson.internal.bind.JsonTreeReader;
21 import java.io.Closeable;
22 import java.io.EOFException;
23 import java.io.IOException;
24 import java.io.Reader;
25 import java.util.Arrays;
26
27 /**
28  * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>)
29  * encoded value as a stream of tokens. This stream includes both literal
30  * values (strings, numbers, booleans, and nulls) as well as the begin and
31  * end delimiters of objects and arrays. The tokens are traversed in
32  * depth-first order, the same order that they appear in the JSON document.
33  * Within JSON objects, name/value pairs are represented by a single token.
34  *
35  * <h3>Parsing JSON</h3>
36  * To create a recursive descent parser for your own JSON streams, first create
37  * an entry point method that creates a {@code JsonReader}.
38  *
39  * <p>Next, create handler methods for each structure in your JSON text. You'll
40  * need a method for each object type and for each array type.
41  * <ul>
42  *   <li>Within <strong>array handling</strong> methods, first call {@link
43  *       #beginArray} to consume the array's opening bracket. Then create a
44  *       while loop that accumulates values, terminating when {@link #hasNext}
45  *       is false. Finally, read the array's closing bracket by calling {@link
46  *       #endArray}.
47  *   <li>Within <strong>object handling</strong> methods, first call {@link
48  *       #beginObject} to consume the object's opening brace. Then create a
49  *       while loop that assigns values to local variables based on their name.
50  *       This loop should terminate when {@link #hasNext} is false. Finally,
51  *       read the object's closing brace by calling {@link #endObject}.
52  * </ul>
53  * <p>When a nested object or array is encountered, delegate to the
54  * corresponding handler method.
55  *
56  * <p>When an unknown name is encountered, strict parsers should fail with an
57  * exception. Lenient parsers should call {@link #skipValue()} to recursively
58  * skip the value's nested tokens, which may otherwise conflict.
59  *
60  * <p>If a value may be null, you should first check using {@link #peek()}.
61  * Null literals can be consumed using either {@link #nextNull()} or {@link
62  * #skipValue()}.
63  *
64  * <h3>Example</h3>
65  * Suppose we'd like to parse a stream of messages such as the following: <pre> {@code
66  * [
67  *   {
68  *     "id": 912345678901,
69  *     "text""How do I read a JSON stream in Java?",
70  *     "geo"null,
71  *     "user": {
72  *       "name""json_newb",
73  *       "followers_count": 41
74  *      }
75  *   },
76  *   {
77  *     "id": 912345678902,
78  *     "text""@json_newb just use JsonReader!",
79  *     "geo": [50.454722, -104.606667],
80  *     "user": {
81  *       "name""jesse",
82  *       "followers_count": 2
83  *     }
84  *   }
85  * ]}</pre>
86  * This code implements the parser for the above structure: <pre>   {@code
87  *
88  *   public List<Message> readJsonStream(InputStream in) throws IOException {
89  *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
90  *     try {
91  *       return readMessagesArray(reader);
92  *     } finally {
93  *       reader.close();
94  *     }
95  *   }
96  *
97  *   public List<Message> readMessagesArray(JsonReader reader) throws IOException {
98  *     List<Message> messages = new ArrayList<Message>();
99  *
100  *     reader.beginArray();
101  *     while (reader.hasNext()) {
102  *       messages.add(readMessage(reader));
103  *     }
104  *     reader.endArray();
105  *     return messages;
106  *   }
107  *
108  *   public Message readMessage(JsonReader reader) throws IOException {
109  *     long id = -1;
110  *     String text = null;
111  *     User user = null;
112  *     List<Double> geo = null;
113  *
114  *     reader.beginObject();
115  *     while (reader.hasNext()) {
116  *       String name = reader.nextName();
117  *       if (name.equals("id")) {
118  *         id = reader.nextLong();
119  *       } else if (name.equals("text")) {
120  *         text = reader.nextString();
121  *       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
122  *         geo = readDoublesArray(reader);
123  *       } else if (name.equals("user")) {
124  *         user = readUser(reader);
125  *       } else {
126  *         reader.skipValue();
127  *       }
128  *     }
129  *     reader.endObject();
130  *     return new Message(id, text, user, geo);
131  *   }
132  *
133  *   public List<Double> readDoublesArray(JsonReader reader) throws IOException {
134  *     List<Double> doubles = new ArrayList<Double>();
135  *
136  *     reader.beginArray();
137  *     while (reader.hasNext()) {
138  *       doubles.add(reader.nextDouble());
139  *     }
140  *     reader.endArray();
141  *     return doubles;
142  *   }
143  *
144  *   public User readUser(JsonReader reader) throws IOException {
145  *     String username = null;
146  *     int followersCount = -1;
147  *
148  *     reader.beginObject();
149  *     while (reader.hasNext()) {
150  *       String name = reader.nextName();
151  *       if (name.equals("name")) {
152  *         username = reader.nextString();
153  *       } else if (name.equals("followers_count")) {
154  *         followersCount = reader.nextInt();
155  *       } else {
156  *         reader.skipValue();
157  *       }
158  *     }
159  *     reader.endObject();
160  *     return new User(username, followersCount);
161  *   }}</pre>
162  *
163  * <h3>Number Handling</h3>
164  * This reader permits numeric values to be read as strings and string values to
165  * be read as numbers. For example, both elements of the JSON array {@code
166  * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}.
167  * This behavior is intended to prevent lossy numeric conversions: double is
168  * JavaScript's only numeric type and very large values like {@code
169  * 9007199254740993} cannot be represented exactly on that platform. To minimize
170  * precision loss, extremely large values should be written and read as strings
171  * in JSON.
172  *
173  * <a name="nonexecuteprefix"/><h3>Non-Execute Prefix</h3>
174  * Web servers that serve private data using JSON may be vulnerable to <a
175  * href="http://en.wikipedia.org/wiki/JSON#Cross-site_request_forgery">Cross-site
176  * request forgery</a> attacks. In such an attack, a malicious site gains access
177  * to a private JSON file by executing it with an HTML {@code <script>} tag.
178  *
179  * <p>Prefixing JSON files with <code>")]}'\n"</code> makes them non-executable
180  * by {@code <script>} tags, disarming the attack. Since the prefix is malformed
181  * JSON, strict parsing fails when it is encountered. This class permits the
182  * non-execute prefix when {@link #setLenient(boolean) lenient parsing} is
183  * enabled.
184  *
185  * <p>Each {@code JsonReader} may be used to read a single JSON stream. Instances
186  * of this class are not thread safe.
187  *
188  * @author Jesse Wilson
189  * @since 1.6
190  */

191 public class JsonReader implements Closeable {
192   /** The only non-execute prefix this parser permits */
193   private static final char[] NON_EXECUTE_PREFIX = ")]}'\n".toCharArray();
194   private static final long MIN_INCOMPLETE_INTEGER = Long.MIN_VALUE / 10;
195
196   private static final int PEEKED_NONE = 0;
197   private static final int PEEKED_BEGIN_OBJECT = 1;
198   private static final int PEEKED_END_OBJECT = 2;
199   private static final int PEEKED_BEGIN_ARRAY = 3;
200   private static final int PEEKED_END_ARRAY = 4;
201   private static final int PEEKED_TRUE = 5;
202   private static final int PEEKED_FALSE = 6;
203   private static final int PEEKED_NULL = 7;
204   private static final int PEEKED_SINGLE_QUOTED = 8;
205   private static final int PEEKED_DOUBLE_QUOTED = 9;
206   private static final int PEEKED_UNQUOTED = 10;
207   /** When this is returned, the string value is stored in peekedString. */
208   private static final int PEEKED_BUFFERED = 11;
209   private static final int PEEKED_SINGLE_QUOTED_NAME = 12;
210   private static final int PEEKED_DOUBLE_QUOTED_NAME = 13;
211   private static final int PEEKED_UNQUOTED_NAME = 14;
212   /** When this is returned, the integer value is stored in peekedLong. */
213   private static final int PEEKED_LONG = 15;
214   private static final int PEEKED_NUMBER = 16;
215   private static final int PEEKED_EOF = 17;
216
217   /* State machine when parsing numbers */
218   private static final int NUMBER_CHAR_NONE = 0;
219   private static final int NUMBER_CHAR_SIGN = 1;
220   private static final int NUMBER_CHAR_DIGIT = 2;
221   private static final int NUMBER_CHAR_DECIMAL = 3;
222   private static final int NUMBER_CHAR_FRACTION_DIGIT = 4;
223   private static final int NUMBER_CHAR_EXP_E = 5;
224   private static final int NUMBER_CHAR_EXP_SIGN = 6;
225   private static final int NUMBER_CHAR_EXP_DIGIT = 7;
226
227   /** The input JSON. */
228   private final Reader in;
229
230   /** True to accept non-spec compliant JSON */
231   private boolean lenient = false;
232
233   /**
234    * Use a manual buffer to easily read and unread upcoming characters, and
235    * also so we can create strings without an intermediate StringBuilder.
236    * We decode literals directly out of this buffer, so it must be at least as
237    * long as the longest token that can be reported as a number.
238    */

239   private final char[] buffer = new char[1024];
240   private int pos = 0;
241   private int limit = 0;
242
243   private int lineNumber = 0;
244   private int lineStart = 0;
245
246   int peeked = PEEKED_NONE;
247
248   /**
249    * A peeked value that was composed entirely of digits with an optional
250    * leading dash. Positive values may not have a leading 0.
251    */

252   private long peekedLong;
253
254   /**
255    * The number of characters in a peeked number literal. Increment 'pos' by
256    * this after reading a number.
257    */

258   private int peekedNumberLength;
259
260   /**
261    * A peeked string that should be parsed on the next doublelong or string.
262    * This is populated before a numeric value is parsed and used if that parsing
263    * fails.
264    */

265   private String peekedString;
266
267   /*
268    * The nesting stack. Using a manual array rather than an ArrayList saves 20%.
269    */

270   private int[] stack = new int[32];
271   private int stackSize = 0;
272   {
273     stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
274   }
275
276   /*
277    * The path members. It corresponds directly to stack: At indices where the
278    * stack contains an object (EMPTY_OBJECT, DANGLING_NAME or NONEMPTY_OBJECT),
279    * pathNames contains the name at this scope. Where it contains an array
280    * (EMPTY_ARRAY, NONEMPTY_ARRAY) pathIndices contains the current index in
281    * that array. Otherwise the value is undefined, and we take advantage of that
282    * by incrementing pathIndices when doing so isn't useful.
283    */

284   private String[] pathNames = new String[32];
285   private int[] pathIndices = new int[32];
286
287   /**
288    * Creates a new instance that reads a JSON-encoded stream from {@code in}.
289    */

290   public JsonReader(Reader in) {
291     if (in == null) {
292       throw new NullPointerException("in == null");
293     }
294     this.in = in;
295   }
296
297   /**
298    * Configure this parser to be liberal in what it accepts. By default,
299    * this parser is strict and only accepts JSON as specified by <a
300    * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the
301    * parser to lenient causes it to ignore the following syntax errors:
302    *
303    * <ul>
304    *   <li>Streams that start with the <a href="#nonexecuteprefix">non-execute
305    *       prefix</a>, <code>")]}'\n"</code>.
306    *   <li>Streams that include multiple top-level values. With strict parsing,
307    *       each stream must contain exactly one top-level value.
308    *   <li>Top-level values of any type. With strict parsing, the top-level
309    *       value must be an object or an array.
310    *   <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
311    *       Double#isInfinite() infinities}.
312    *   <li>End of line comments starting with {@code //} or {@code #} and
313    *       ending with a newline character.
314    *   <li>C-style comments starting with {@code /*} and ending with
315    *       {@code *}{@code /}. Such comments may not be nested.
316    *   <li>Names that are unquoted or {@code 'single quoted'}.
317    *   <li>Strings that are unquoted or {@code 'single quoted'}.
318    *   <li>Array elements separated by {@code ;} instead of {@code ,}.
319    *   <li>Unnecessary array separators. These are interpreted as if null
320    *       was the omitted value.
321    *   <li>Names and values separated by {@code =} or {@code =>} instead of
322    *       {@code :}.
323    *   <li>Name/value pairs separated by {@code ;} instead of {@code ,}.
324    * </ul>
325    */

326   public final void setLenient(boolean lenient) {
327     this.lenient = lenient;
328   }
329
330   /**
331    * Returns true if this parser is liberal in what it accepts.
332    */

333   public final boolean isLenient() {
334     return lenient;
335   }
336
337   /**
338    * Consumes the next token from the JSON stream and asserts that it is the
339    * beginning of a new array.
340    */

341   public void beginArray() throws IOException {
342     int p = peeked;
343     if (p == PEEKED_NONE) {
344       p = doPeek();
345     }
346     if (p == PEEKED_BEGIN_ARRAY) {
347       push(JsonScope.EMPTY_ARRAY);
348       pathIndices[stackSize - 1] = 0;
349       peeked = PEEKED_NONE;
350     } else {
351       throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek() + locationString());
352     }
353   }
354
355   /**
356    * Consumes the next token from the JSON stream and asserts that it is the
357    * end of the current array.
358    */

359   public void endArray() throws IOException {
360     int p = peeked;
361     if (p == PEEKED_NONE) {
362       p = doPeek();
363     }
364     if (p == PEEKED_END_ARRAY) {
365       stackSize--;
366       pathIndices[stackSize - 1]++;
367       peeked = PEEKED_NONE;
368     } else {
369       throw new IllegalStateException("Expected END_ARRAY but was " + peek() + locationString());
370     }
371   }
372
373   /**
374    * Consumes the next token from the JSON stream and asserts that it is the
375    * beginning of a new object.
376    */

377   public void beginObject() throws IOException {
378     int p = peeked;
379     if (p == PEEKED_NONE) {
380       p = doPeek();
381     }
382     if (p == PEEKED_BEGIN_OBJECT) {
383       push(JsonScope.EMPTY_OBJECT);
384       peeked = PEEKED_NONE;
385     } else {
386       throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString());
387     }
388   }
389
390   /**
391    * Consumes the next token from the JSON stream and asserts that it is the
392    * end of the current object.
393    */

394   public void endObject() throws IOException {
395     int p = peeked;
396     if (p == PEEKED_NONE) {
397       p = doPeek();
398     }
399     if (p == PEEKED_END_OBJECT) {
400       stackSize--;
401       pathNames[stackSize] = null// Free the last path name so that it can be garbage collected!
402       pathIndices[stackSize - 1]++;
403       peeked = PEEKED_NONE;
404     } else {
405       throw new IllegalStateException("Expected END_OBJECT but was " + peek() + locationString());
406     }
407   }
408
409   /**
410    * Returns true if the current array or object has another element.
411    */

412   public boolean hasNext() throws IOException {
413     int p = peeked;
414     if (p == PEEKED_NONE) {
415       p = doPeek();
416     }
417     return p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY;
418   }
419
420   /**
421    * Returns the type of the next token without consuming it.
422    */

423   public JsonToken peek() throws IOException {
424     int p = peeked;
425     if (p == PEEKED_NONE) {
426       p = doPeek();
427     }
428
429     switch (p) {
430     case PEEKED_BEGIN_OBJECT:
431       return JsonToken.BEGIN_OBJECT;
432     case PEEKED_END_OBJECT:
433       return JsonToken.END_OBJECT;
434     case PEEKED_BEGIN_ARRAY:
435       return JsonToken.BEGIN_ARRAY;
436     case PEEKED_END_ARRAY:
437       return JsonToken.END_ARRAY;
438     case PEEKED_SINGLE_QUOTED_NAME:
439     case PEEKED_DOUBLE_QUOTED_NAME:
440     case PEEKED_UNQUOTED_NAME:
441       return JsonToken.NAME;
442     case PEEKED_TRUE:
443     case PEEKED_FALSE:
444       return JsonToken.BOOLEAN;
445     case PEEKED_NULL:
446       return JsonToken.NULL;
447     case PEEKED_SINGLE_QUOTED:
448     case PEEKED_DOUBLE_QUOTED:
449     case PEEKED_UNQUOTED:
450     case PEEKED_BUFFERED:
451       return JsonToken.STRING;
452     case PEEKED_LONG:
453     case PEEKED_NUMBER:
454       return JsonToken.NUMBER;
455     case PEEKED_EOF:
456       return JsonToken.END_DOCUMENT;
457     default:
458       throw new AssertionError();
459     }
460   }
461
462   int doPeek() throws IOException {
463     int peekStack = stack[stackSize - 1];
464     if (peekStack == JsonScope.EMPTY_ARRAY) {
465       stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
466     } else if (peekStack == JsonScope.NONEMPTY_ARRAY) {
467       // Look for a comma before the next element.
468       int c = nextNonWhitespace(true);
469       switch (c) {
470       case ']':
471         return peeked = PEEKED_END_ARRAY;
472       case ';':
473         checkLenient(); // fall-through
474       case ',':
475         break;
476       default:
477         throw syntaxError("Unterminated array");
478       }
479     } else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
480       stack[stackSize - 1] = JsonScope.DANGLING_NAME;
481       // Look for a comma before the next element.
482       if (peekStack == JsonScope.NONEMPTY_OBJECT) {
483         int c = nextNonWhitespace(true);
484         switch (c) {
485         case '}':
486           return peeked = PEEKED_END_OBJECT;
487         case ';':
488           checkLenient(); // fall-through
489         case ',':
490           break;
491         default:
492           throw syntaxError("Unterminated object");
493         }
494       }
495       int c = nextNonWhitespace(true);
496       switch (c) {
497       case '"':
498         return peeked = PEEKED_DOUBLE_QUOTED_NAME;
499       case '\'':
500         checkLenient();
501         return peeked = PEEKED_SINGLE_QUOTED_NAME;
502       case '}':
503         if (peekStack != JsonScope.NONEMPTY_OBJECT) {
504           return peeked = PEEKED_END_OBJECT;
505         } else {
506           throw syntaxError("Expected name");
507         }
508       default:
509         checkLenient();
510         pos--; // Don't consume the first character in an unquoted string.
511         if (isLiteral((char) c)) {
512           return peeked = PEEKED_UNQUOTED_NAME;
513         } else {
514           throw syntaxError("Expected name");
515         }
516       }
517     } else if (peekStack == JsonScope.DANGLING_NAME) {
518       stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
519       // Look for a colon before the value.
520       int c = nextNonWhitespace(true);
521       switch (c) {
522       case ':':
523         break;
524       case '=':
525         checkLenient();
526         if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
527           pos++;
528         }
529         break;
530       default:
531         throw syntaxError("Expected ':'");
532       }
533     } else if (peekStack == JsonScope.EMPTY_DOCUMENT) {
534       if (lenient) {
535         consumeNonExecutePrefix();
536       }
537       stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
538     } else if (peekStack == JsonScope.NONEMPTY_DOCUMENT) {
539       int c = nextNonWhitespace(false);
540       if (c == -1) {
541         return peeked = PEEKED_EOF;
542       } else {
543         checkLenient();
544         pos--;
545       }
546     } else if (peekStack == JsonScope.CLOSED) {
547       throw new IllegalStateException("JsonReader is closed");
548     }
549
550     int c = nextNonWhitespace(true);
551     switch (c) {
552     case ']':
553       if (peekStack == JsonScope.EMPTY_ARRAY) {
554         return peeked = PEEKED_END_ARRAY;
555       }
556       // fall-through to handle ",]"
557     case ';':
558     case ',':
559       // In lenient mode, a 0-length literal in an array means 'null'.
560       if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
561         checkLenient();
562         pos--;
563         return peeked = PEEKED_NULL;
564       } else {
565         throw syntaxError("Unexpected value");
566       }
567     case '\'':
568       checkLenient();
569       return peeked = PEEKED_SINGLE_QUOTED;
570     case '"':
571       return peeked = PEEKED_DOUBLE_QUOTED;
572     case '[':
573       return peeked = PEEKED_BEGIN_ARRAY;
574     case '{':
575       return peeked = PEEKED_BEGIN_OBJECT;
576     default:
577       pos--; // Don't consume the first character in a literal value.
578     }
579
580     int result = peekKeyword();
581     if (result != PEEKED_NONE) {
582       return result;
583     }
584
585     result = peekNumber();
586     if (result != PEEKED_NONE) {
587       return result;
588     }
589
590     if (!isLiteral(buffer[pos])) {
591       throw syntaxError("Expected value");
592     }
593
594     checkLenient();
595     return peeked = PEEKED_UNQUOTED;
596   }
597
598   private int peekKeyword() throws IOException {
599     // Figure out which keyword we're matching against by its first character.
600     char c = buffer[pos];
601     String keyword;
602     String keywordUpper;
603     int peeking;
604     if (c == 't' || c == 'T') {
605       keyword = "true";
606       keywordUpper = "TRUE";
607       peeking = PEEKED_TRUE;
608     } else if (c == 'f' || c == 'F') {
609       keyword = "false";
610       keywordUpper = "FALSE";
611       peeking = PEEKED_FALSE;
612     } else if (c == 'n' || c == 'N') {
613       keyword = "null";
614       keywordUpper = "NULL";
615       peeking = PEEKED_NULL;
616     } else {
617       return PEEKED_NONE;
618     }
619
620     // Confirm that chars [1..length) match the keyword.
621     int length = keyword.length();
622     for (int i = 1; i < length; i++) {
623       if (pos + i >= limit && !fillBuffer(i + 1)) {
624         return PEEKED_NONE;
625       }
626       c = buffer[pos + i];
627       if (c != keyword.charAt(i) && c != keywordUpper.charAt(i)) {
628         return PEEKED_NONE;
629       }
630     }
631
632     if ((pos + length < limit || fillBuffer(length + 1))
633         && isLiteral(buffer[pos + length])) {
634       return PEEKED_NONE; // Don't match trues, falsey or nullsoft!
635     }
636
637     // We've found the keyword followed either by EOF or by a non-literal character.
638     pos += length;
639     return peeked = peeking;
640   }
641
642   private int peekNumber() throws IOException {
643     // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
644     char[] buffer = this.buffer;
645     int p = pos;
646     int l = limit;
647
648     long value = 0; // Negative to accommodate Long.MIN_VALUE more easily.
649     boolean negative = false;
650     boolean fitsInLong = true;
651     int last = NUMBER_CHAR_NONE;
652
653     int i = 0;
654
655     charactersOfNumber:
656     for (; true; i++) {
657       if (p + i == l) {
658         if (i == buffer.length) {
659           // Though this looks like a well-formed number, it's too long to continue reading. Give up
660           // and let the application handle this as an unquoted literal.
661           return PEEKED_NONE;
662         }
663         if (!fillBuffer(i + 1)) {
664           break;
665         }
666         p = pos;
667         l = limit;
668       }
669
670       char c = buffer[p + i];
671       switch (c) {
672       case '-':
673         if (last == NUMBER_CHAR_NONE) {
674           negative = true;
675           last = NUMBER_CHAR_SIGN;
676           continue;
677         } else if (last == NUMBER_CHAR_EXP_E) {
678           last = NUMBER_CHAR_EXP_SIGN;
679           continue;
680         }
681         return PEEKED_NONE;
682
683       case '+':
684         if (last == NUMBER_CHAR_EXP_E) {
685           last = NUMBER_CHAR_EXP_SIGN;
686           continue;
687         }
688         return PEEKED_NONE;
689
690       case 'e':
691       case 'E':
692         if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT) {
693           last = NUMBER_CHAR_EXP_E;
694           continue;
695         }
696         return PEEKED_NONE;
697
698       case '.':
699         if (last == NUMBER_CHAR_DIGIT) {
700           last = NUMBER_CHAR_DECIMAL;
701           continue;
702         }
703         return PEEKED_NONE;
704
705       default:
706         if (c < '0' || c > '9') {
707           if (!isLiteral(c)) {
708             break charactersOfNumber;
709           }
710           return PEEKED_NONE;
711         }
712         if (last == NUMBER_CHAR_SIGN || last == NUMBER_CHAR_NONE) {
713           value = -(c - '0');
714           last = NUMBER_CHAR_DIGIT;
715         } else if (last == NUMBER_CHAR_DIGIT) {
716           if (value == 0) {
717             return PEEKED_NONE; // Leading '0' prefix is not allowed (since it could be octal).
718           }
719           long newValue = value * 10 - (c - '0');
720           fitsInLong &= value > MIN_INCOMPLETE_INTEGER
721               || (value == MIN_INCOMPLETE_INTEGER && newValue < value);
722           value = newValue;
723         } else if (last == NUMBER_CHAR_DECIMAL) {
724           last = NUMBER_CHAR_FRACTION_DIGIT;
725         } else if (last == NUMBER_CHAR_EXP_E || last == NUMBER_CHAR_EXP_SIGN) {
726           last = NUMBER_CHAR_EXP_DIGIT;
727         }
728       }
729     }
730
731     // We've read a complete number. Decide if it's a PEEKED_LONG or a PEEKED_NUMBER.
732     if (last == NUMBER_CHAR_DIGIT && fitsInLong && (value != Long.MIN_VALUE || negative) && (value!=0 || false==negative)) {
733       peekedLong = negative ? value : -value;
734       pos += i;
735       return peeked = PEEKED_LONG;
736     } else if (last == NUMBER_CHAR_DIGIT || last == NUMBER_CHAR_FRACTION_DIGIT
737         || last == NUMBER_CHAR_EXP_DIGIT) {
738       peekedNumberLength = i;
739       return peeked = PEEKED_NUMBER;
740     } else {
741       return PEEKED_NONE;
742     }
743   }
744
745   private boolean isLiteral(char c) throws IOException {
746     switch (c) {
747     case '/':
748     case '\\':
749     case ';':
750     case '#':
751     case '=':
752       checkLenient(); // fall-through
753     case '{':
754     case '}':
755     case '[':
756     case ']':
757     case ':':
758     case ',':
759     case ' ':
760     case '\t':
761     case '\f':
762     case '\r':
763     case '\n':
764       return false;
765     default:
766       return true;
767     }
768   }
769
770   /**
771    * Returns the next token, a {@link com.google.gson.stream.JsonToken#NAME property name}, and
772    * consumes it.
773    *
774    * @throws java.io.IOException if the next token in the stream is not a property
775    *     name.
776    */

777   public String nextName() throws IOException {
778     int p = peeked;
779     if (p == PEEKED_NONE) {
780       p = doPeek();
781     }
782     String result;
783     if (p == PEEKED_UNQUOTED_NAME) {
784       result = nextUnquotedValue();
785     } else if (p == PEEKED_SINGLE_QUOTED_NAME) {
786       result = nextQuotedValue('\'');
787     } else if (p == PEEKED_DOUBLE_QUOTED_NAME) {
788       result = nextQuotedValue('"');
789     } else {
790       throw new IllegalStateException("Expected a name but was " + peek() + locationString());
791     }
792     peeked = PEEKED_NONE;
793     pathNames[stackSize - 1] = result;
794     return result;
795   }
796
797   /**
798    * Returns the {@link com.google.gson.stream.JsonToken#STRING string} value of the next token,
799    * consuming it. If the next token is a number, this method will return its
800    * string form.
801    *
802    * @throws IllegalStateException if the next token is not a string or if
803    *     this reader is closed.
804    */

805   public String nextString() throws IOException {
806     int p = peeked;
807     if (p == PEEKED_NONE) {
808       p = doPeek();
809     }
810     String result;
811     if (p == PEEKED_UNQUOTED) {
812       result = nextUnquotedValue();
813     } else if (p == PEEKED_SINGLE_QUOTED) {
814       result = nextQuotedValue('\'');
815     } else if (p == PEEKED_DOUBLE_QUOTED) {
816       result = nextQuotedValue('"');
817     } else if (p == PEEKED_BUFFERED) {
818       result = peekedString;
819       peekedString = null;
820     } else if (p == PEEKED_LONG) {
821       result = Long.toString(peekedLong);
822     } else if (p == PEEKED_NUMBER) {
823       result = new String(buffer, pos, peekedNumberLength);
824       pos += peekedNumberLength;
825     } else {
826       throw new IllegalStateException("Expected a string but was " + peek() + locationString());
827     }
828     peeked = PEEKED_NONE;
829     pathIndices[stackSize - 1]++;
830     return result;
831   }
832
833   /**
834    * Returns the {@link com.google.gson.stream.JsonToken#BOOLEAN boolean} value of the next token,
835    * consuming it.
836    *
837    * @throws IllegalStateException if the next token is not a boolean or if
838    *     this reader is closed.
839    */

840   public boolean nextBoolean() throws IOException {
841     int p = peeked;
842     if (p == PEEKED_NONE) {
843       p = doPeek();
844     }
845     if (p == PEEKED_TRUE) {
846       peeked = PEEKED_NONE;
847       pathIndices[stackSize - 1]++;
848       return true;
849     } else if (p == PEEKED_FALSE) {
850       peeked = PEEKED_NONE;
851       pathIndices[stackSize - 1]++;
852       return false;
853     }
854     throw new IllegalStateException("Expected a boolean but was " + peek() + locationString());
855   }
856
857   /**
858    * Consumes the next token from the JSON stream and asserts that it is a
859    * literal null.
860    *
861    * @throws IllegalStateException if the next token is not null or if this
862    *     reader is closed.
863    */

864   public void nextNull() throws IOException {
865     int p = peeked;
866     if (p == PEEKED_NONE) {
867       p = doPeek();
868     }
869     if (p == PEEKED_NULL) {
870       peeked = PEEKED_NONE;
871       pathIndices[stackSize - 1]++;
872     } else {
873       throw new IllegalStateException("Expected null but was " + peek() + locationString());
874     }
875   }
876
877   /**
878    * Returns the {@link com.google.gson.stream.JsonToken#NUMBER double} value of the next token,
879    * consuming it. If the next token is a string, this method will attempt to
880    * parse it as a double using {@link Double#parseDouble(String)}.
881    *
882    * @throws IllegalStateException if the next token is not a literal value.
883    * @throws NumberFormatException if the next literal value cannot be parsed
884    *     as a double, or is non-finite.
885    */

886   public double nextDouble() throws IOException {
887     int p = peeked;
888     if (p == PEEKED_NONE) {
889       p = doPeek();
890     }
891
892     if (p == PEEKED_LONG) {
893       peeked = PEEKED_NONE;
894       pathIndices[stackSize - 1]++;
895       return (double) peekedLong;
896     }
897
898     if (p == PEEKED_NUMBER) {
899       peekedString = new String(buffer, pos, peekedNumberLength);
900       pos += peekedNumberLength;
901     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
902       peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
903     } else if (p == PEEKED_UNQUOTED) {
904       peekedString = nextUnquotedValue();
905     } else if (p != PEEKED_BUFFERED) {
906       throw new IllegalStateException("Expected a double but was " + peek() + locationString());
907     }
908
909     peeked = PEEKED_BUFFERED;
910     double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
911     if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
912       throw new MalformedJsonException(
913           "JSON forbids NaN and infinities: " + result + locationString());
914     }
915     peekedString = null;
916     peeked = PEEKED_NONE;
917     pathIndices[stackSize - 1]++;
918     return result;
919   }
920
921   /**
922    * Returns the {@link com.google.gson.stream.JsonToken#NUMBER long} value of the next token,
923    * consuming it. If the next token is a string, this method will attempt to
924    * parse it as a long. If the next token's numeric value cannot be exactly
925    * represented by a Java {@code long}, this method throws.
926    *
927    * @throws IllegalStateException if the next token is not a literal value.
928    * @throws NumberFormatException if the next literal value cannot be parsed
929    *     as a number, or exactly represented as a long.
930    */

931   public long nextLong() throws IOException {
932     int p = peeked;
933     if (p == PEEKED_NONE) {
934       p = doPeek();
935     }
936
937     if (p == PEEKED_LONG) {
938       peeked = PEEKED_NONE;
939       pathIndices[stackSize - 1]++;
940       return peekedLong;
941     }
942
943     if (p == PEEKED_NUMBER) {
944       peekedString = new String(buffer, pos, peekedNumberLength);
945       pos += peekedNumberLength;
946     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED || p == PEEKED_UNQUOTED) {
947       if (p == PEEKED_UNQUOTED) {
948         peekedString = nextUnquotedValue();
949       } else {
950         peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
951       }
952       try {
953         long result = Long.parseLong(peekedString);
954         peeked = PEEKED_NONE;
955         pathIndices[stackSize - 1]++;
956         return result;
957       } catch (NumberFormatException ignored) {
958         // Fall back to parse as a double below.
959       }
960     } else {
961       throw new IllegalStateException("Expected a long but was " + peek() + locationString());
962     }
963
964     peeked = PEEKED_BUFFERED;
965     double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
966     long result = (long) asDouble;
967     if (result != asDouble) { // Make sure no precision was lost casting to 'long'.
968       throw new NumberFormatException("Expected a long but was " + peekedString + locationString());
969     }
970     peekedString = null;
971     peeked = PEEKED_NONE;
972     pathIndices[stackSize - 1]++;
973     return result;
974   }
975
976   /**
977    * Returns the string up to but not including {@code quote}, unescaping any
978    * character escape sequences encountered along the way. The opening quote
979    * should have already been read. This consumes the closing quote, but does
980    * not include it in the returned string.
981    *
982    * @param quote either ' or ".
983    * @throws NumberFormatException if any unicode escape sequences are
984    *     malformed.
985    */

986   private String nextQuotedValue(char quote) throws IOException {
987     // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
988     char[] buffer = this.buffer;
989     StringBuilder builder = null;
990     while (true) {
991       int p = pos;
992       int l = limit;
993       /* the index of the first character not yet appended to the builder. */
994       int start = p;
995       while (p < l) {
996         int c = buffer[p++];
997
998         if (c == quote) {
999           pos = p;
1000           int len = p - start - 1;
1001           if (builder == null) {
1002             return new String(buffer, start, len);
1003           } else {
1004             builder.append(buffer, start, len);
1005             return builder.toString();
1006           }
1007         } else if (c == '\\') {
1008           pos = p;
1009           int len = p - start - 1;
1010           if (builder == null) {
1011             int estimatedLength = (len + 1) * 2;
1012             builder = new StringBuilder(Math.max(estimatedLength, 16));
1013           }
1014           builder.append(buffer, start, len);
1015           builder.append(readEscapeCharacter());
1016           p = pos;
1017           l = limit;
1018           start = p;
1019         } else if (c == '\n') {
1020           lineNumber++;
1021           lineStart = p;
1022         }
1023       }
1024
1025       if (builder == null) {
1026         int estimatedLength = (p - start) * 2;
1027         builder = new StringBuilder(Math.max(estimatedLength, 16));
1028       }
1029       builder.append(buffer, start, p - start);
1030       pos = p;
1031       if (!fillBuffer(1)) {
1032         throw syntaxError("Unterminated string");
1033       }
1034     }
1035   }
1036
1037   /**
1038    * Returns an unquoted value as a string.
1039    */

1040   @SuppressWarnings("fallthrough")
1041   private String nextUnquotedValue() throws IOException {
1042     StringBuilder builder = null;
1043     int i = 0;
1044
1045     findNonLiteralCharacter:
1046     while (true) {
1047       for (; pos + i < limit; i++) {
1048         switch (buffer[pos + i]) {
1049         case '/':
1050         case '\\':
1051         case ';':
1052         case '#':
1053         case '=':
1054           checkLenient(); // fall-through
1055         case '{':
1056         case '}':
1057         case '[':
1058         case ']':
1059         case ':':
1060         case ',':
1061         case ' ':
1062         case '\t':
1063         case '\f':
1064         case '\r':
1065         case '\n':
1066           break findNonLiteralCharacter;
1067         }
1068       }
1069
1070       // Attempt to load the entire literal into the buffer at once.
1071       if (i < buffer.length) {
1072         if (fillBuffer(i + 1)) {
1073           continue;
1074         } else {
1075           break;
1076         }
1077       }
1078
1079       // use a StringBuilder when the value is too long. This is too long to be a number!
1080       if (builder == null) {
1081         builder = new StringBuilder(Math.max(i,16));
1082       }
1083       builder.append(buffer, pos, i);
1084       pos += i;
1085       i = 0;
1086       if (!fillBuffer(1)) {
1087         break;
1088       }
1089     }
1090    
1091     String result = (null == builder) ? new String(buffer, pos, i) : builder.append(buffer, pos, i).toString();
1092     pos += i;
1093     return result;
1094   }
1095
1096   private void skipQuotedValue(char quote) throws IOException {
1097     // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
1098     char[] buffer = this.buffer;
1099     do {
1100       int p = pos;
1101       int l = limit;
1102       /* the index of the first character not yet appended to the builder. */
1103       while (p < l) {
1104         int c = buffer[p++];
1105         if (c == quote) {
1106           pos = p;
1107           return;
1108         } else if (c == '\\') {
1109           pos = p;
1110           readEscapeCharacter();
1111           p = pos;
1112           l = limit;
1113         } else if (c == '\n') {
1114           lineNumber++;
1115           lineStart = p;
1116         }
1117       }
1118       pos = p;
1119     } while (fillBuffer(1));
1120     throw syntaxError("Unterminated string");
1121   }
1122
1123   private void skipUnquotedValue() throws IOException {
1124     do {
1125       int i = 0;
1126       for (; pos + i < limit; i++) {
1127         switch (buffer[pos + i]) {
1128         case '/':
1129         case '\\':
1130         case ';':
1131         case '#':
1132         case '=':
1133           checkLenient(); // fall-through
1134         case '{':
1135         case '}':
1136         case '[':
1137         case ']':
1138         case ':':
1139         case ',':
1140         case ' ':
1141         case '\t':
1142         case '\f':
1143         case '\r':
1144         case '\n':
1145           pos += i;
1146           return;
1147         }
1148       }
1149       pos += i;
1150     } while (fillBuffer(1));
1151   }
1152
1153   /**
1154    * Returns the {@link com.google.gson.stream.JsonToken#NUMBER int} value of the next token,
1155    * consuming it. If the next token is a string, this method will attempt to
1156    * parse it as an int. If the next token's numeric value cannot be exactly
1157    * represented by a Java {@code int}, this method throws.
1158    *
1159    * @throws IllegalStateException if the next token is not a literal value.
1160    * @throws NumberFormatException if the next literal value cannot be parsed
1161    *     as a number, or exactly represented as an int.
1162    */

1163   public int nextInt() throws IOException {
1164     int p = peeked;
1165     if (p == PEEKED_NONE) {
1166       p = doPeek();
1167     }
1168
1169     int result;
1170     if (p == PEEKED_LONG) {
1171       result = (int) peekedLong;
1172       if (peekedLong != result) { // Make sure no precision was lost casting to 'int'.
1173         throw new NumberFormatException("Expected an int but was " + peekedLong + locationString());
1174       }
1175       peeked = PEEKED_NONE;
1176       pathIndices[stackSize - 1]++;
1177       return result;
1178     }
1179
1180     if (p == PEEKED_NUMBER) {
1181       peekedString = new String(buffer, pos, peekedNumberLength);
1182       pos += peekedNumberLength;
1183     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED || p == PEEKED_UNQUOTED) {
1184       if (p == PEEKED_UNQUOTED) {
1185         peekedString = nextUnquotedValue();
1186       } else {
1187         peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"');
1188       }
1189       try {
1190         result = Integer.parseInt(peekedString);
1191         peeked = PEEKED_NONE;
1192         pathIndices[stackSize - 1]++;
1193         return result;
1194       } catch (NumberFormatException ignored) {
1195         // Fall back to parse as a double below.
1196       }
1197     } else {
1198       throw new IllegalStateException("Expected an int but was " + peek() + locationString());
1199     }
1200
1201     peeked = PEEKED_BUFFERED;
1202     double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
1203     result = (int) asDouble;
1204     if (result != asDouble) { // Make sure no precision was lost casting to 'int'.
1205       throw new NumberFormatException("Expected an int but was " + peekedString + locationString());
1206     }
1207     peekedString = null;
1208     peeked = PEEKED_NONE;
1209     pathIndices[stackSize - 1]++;
1210     return result;
1211   }
1212
1213   /**
1214    * Closes this JSON reader and the underlying {@link java.io.Reader}.
1215    */

1216   public void close() throws IOException {
1217     peeked = PEEKED_NONE;
1218     stack[0] = JsonScope.CLOSED;
1219     stackSize = 1;
1220     in.close();
1221   }
1222
1223   /**
1224    * Skips the next value recursively. If it is an object or array, all nested
1225    * elements are skipped. This method is intended for use when the JSON token
1226    * stream contains unrecognized or unhandled values.
1227    */

1228   public void skipValue() throws IOException {
1229     int count = 0;
1230     do {
1231       int p = peeked;
1232       if (p == PEEKED_NONE) {
1233         p = doPeek();
1234       }
1235
1236       if (p == PEEKED_BEGIN_ARRAY) {
1237         push(JsonScope.EMPTY_ARRAY);
1238         count++;
1239       } else if (p == PEEKED_BEGIN_OBJECT) {
1240         push(JsonScope.EMPTY_OBJECT);
1241         count++;
1242       } else if (p == PEEKED_END_ARRAY) {
1243         stackSize--;
1244         count--;
1245       } else if (p == PEEKED_END_OBJECT) {
1246         stackSize--;
1247         count--;
1248       } else if (p == PEEKED_UNQUOTED_NAME || p == PEEKED_UNQUOTED) {
1249         skipUnquotedValue();
1250       } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_SINGLE_QUOTED_NAME) {
1251         skipQuotedValue('\'');
1252       } else if (p == PEEKED_DOUBLE_QUOTED || p == PEEKED_DOUBLE_QUOTED_NAME) {
1253         skipQuotedValue('"');
1254       } else if (p == PEEKED_NUMBER) {
1255         pos += peekedNumberLength;
1256       }
1257       peeked = PEEKED_NONE;
1258     } while (count != 0);
1259
1260     pathIndices[stackSize - 1]++;
1261     pathNames[stackSize - 1] = "null";
1262   }
1263
1264   private void push(int newTop) {
1265     if (stackSize == stack.length) {
1266       int newLength = stackSize * 2;
1267       stack = Arrays.copyOf(stack, newLength);
1268       pathIndices = Arrays.copyOf(pathIndices, newLength);
1269       pathNames = Arrays.copyOf(pathNames, newLength);
1270     }
1271     stack[stackSize++] = newTop;
1272   }
1273
1274   /**
1275    * Returns true once {@code limit - pos >= minimum}. If the data is
1276    * exhausted before that many characters are available, this returns
1277    * false.
1278    */

1279   private boolean fillBuffer(int minimum) throws IOException {
1280     char[] buffer = this.buffer;
1281     lineStart -= pos;
1282     if (limit != pos) {
1283       limit -= pos;
1284       System.arraycopy(buffer, pos, buffer, 0, limit);
1285     } else {
1286       limit = 0;
1287     }
1288
1289     pos = 0;
1290     int total;
1291     while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) {
1292       limit += total;
1293
1294       // if this is the first read, consume an optional byte order mark (BOM) if it exists
1295       if (lineNumber == 0 && lineStart == 0 && limit > 0 && buffer[0] == '\ufeff') {
1296         pos++;
1297         lineStart++;
1298         minimum++;
1299       }
1300
1301       if (limit >= minimum) {
1302         return true;
1303       }
1304     }
1305     return false;
1306   }
1307
1308   /**
1309    * Returns the next character in the stream that is neither whitespace nor a
1310    * part of a comment. When this returns, the returned character is always at
1311    * {@code buffer[pos-1]}; this means the caller can always push back the
1312    * returned character by decrementing {@code pos}.
1313    */

1314   private int nextNonWhitespace(boolean throwOnEof) throws IOException {
1315     /*
1316      * This code uses ugly local variables 'p' and 'l' representing the 'pos'
1317      * and 'limit' fields respectively. Using locals rather than fields saves
1318      * a few field reads for each whitespace character in a pretty-printed
1319      * document, resulting in a 5% speedup. We need to flush 'p' to its field
1320      * before any (potentially indirect) call to fillBuffer() and reread both
1321      * 'p' and 'l' after any (potentially indirect) call to the same method.
1322      */

1323     char[] buffer = this.buffer;
1324     int p = pos;
1325     int l = limit;
1326     while (true) {
1327       if (p == l) {
1328         pos = p;
1329         if (!fillBuffer(1)) {
1330           break;
1331         }
1332         p = pos;
1333         l = limit;
1334       }
1335
1336       int c = buffer[p++];
1337       if (c == '\n') {
1338         lineNumber++;
1339         lineStart = p;
1340         continue;
1341       } else if (c == ' ' || c == '\r' || c == '\t') {
1342         continue;
1343       }
1344
1345       if (c == '/') {
1346         pos = p;
1347         if (p == l) {
1348           pos--; // push back '/' so it's still in the buffer when this method returns
1349           boolean charsLoaded = fillBuffer(2);
1350           pos++; // consume the '/' again
1351           if (!charsLoaded) {
1352             return c;
1353           }
1354         }
1355
1356         checkLenient();
1357         char peek = buffer[pos];
1358         switch (peek) {
1359         case '*':
1360           // skip a /* c-style comment */
1361           pos++;
1362           if (!skipTo("*/")) {
1363             throw syntaxError("Unterminated comment");
1364           }
1365           p = pos + 2;
1366           l = limit;
1367           continue;
1368
1369         case '/':
1370           // skip a // end-of-line comment
1371           pos++;
1372           skipToEndOfLine();
1373           p = pos;
1374           l = limit;
1375           continue;
1376
1377         default:
1378           return c;
1379         }
1380       } else if (c == '#') {
1381         pos = p;
1382         /*
1383          * Skip a # hash end-of-line comment. The JSON RFC doesn't
1384          * specify this behaviour, but it's required to parse
1385          * existing documents. See http://b/2571423.
1386          */

1387         checkLenient();
1388         skipToEndOfLine();
1389         p = pos;
1390         l = limit;
1391       } else {
1392         pos = p;
1393         return c;
1394       }
1395     }
1396     if (throwOnEof) {
1397       throw new EOFException("End of input" + locationString());
1398     } else {
1399       return -1;
1400     }
1401   }
1402
1403   private void checkLenient() throws IOException {
1404     if (!lenient) {
1405       throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON");
1406     }
1407   }
1408
1409   /**
1410    * Advances the position until after the next newline character. If the line
1411    * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
1412    * caller.
1413    */

1414   private void skipToEndOfLine() throws IOException {
1415     while (pos < limit || fillBuffer(1)) {
1416       char c = buffer[pos++];
1417       if (c == '\n') {
1418         lineNumber++;
1419         lineStart = pos;
1420         break;
1421       } else if (c == '\r') {
1422         break;
1423       }
1424     }
1425   }
1426
1427   /**
1428    * @param toFind a string to search for. Must not contain a newline.
1429    */

1430   private boolean skipTo(String toFind) throws IOException {
1431     int length = toFind.length();
1432     outer:
1433     for (; pos + length <= limit || fillBuffer(length); pos++) {
1434       if (buffer[pos] == '\n') {
1435         lineNumber++;
1436         lineStart = pos + 1;
1437         continue;
1438       }
1439       for (int c = 0; c < length; c++) {
1440         if (buffer[pos + c] != toFind.charAt(c)) {
1441           continue outer;
1442         }
1443       }
1444       return true;
1445     }
1446     return false;
1447   }
1448
1449   @Override public String toString() {
1450     return getClass().getSimpleName() + locationString();
1451   }
1452
1453   String locationString() {
1454     int line = lineNumber + 1;
1455     int column = pos - lineStart + 1;
1456     return " at line " + line + " column " + column + " path " + getPath();
1457   }
1458
1459   /**
1460    * Returns a <a href="http://goessner.net/articles/JsonPath/">JsonPath</a> to
1461    * the current location in the JSON value.
1462    */

1463   public String getPath() {
1464     StringBuilder result = new StringBuilder().append('$');
1465     for (int i = 0, size = stackSize; i < size; i++) {
1466       switch (stack[i]) {
1467         case JsonScope.EMPTY_ARRAY:
1468         case JsonScope.NONEMPTY_ARRAY:
1469           result.append('[').append(pathIndices[i]).append(']');
1470           break;
1471
1472         case JsonScope.EMPTY_OBJECT:
1473         case JsonScope.DANGLING_NAME:
1474         case JsonScope.NONEMPTY_OBJECT:
1475           result.append('.');
1476           if (pathNames[i] != null) {
1477             result.append(pathNames[i]);
1478           }
1479           break;
1480
1481         case JsonScope.NONEMPTY_DOCUMENT:
1482         case JsonScope.EMPTY_DOCUMENT:
1483         case JsonScope.CLOSED:
1484           break;
1485       }
1486     }
1487     return result.toString();
1488   }
1489
1490   /**
1491    * Unescapes the character identified by the character or characters that
1492    * immediately follow a backslash. The backslash '\' should have already
1493    * been read. This supports both unicode escapes "u000A" and two-character
1494    * escapes "\n".
1495    *
1496    * @throws NumberFormatException if any unicode escape sequences are
1497    *     malformed.
1498    */

1499   private char readEscapeCharacter() throws IOException {
1500     if (pos == limit && !fillBuffer(1)) {
1501       throw syntaxError("Unterminated escape sequence");
1502     }
1503
1504     char escaped = buffer[pos++];
1505     switch (escaped) {
1506     case 'u':
1507       if (pos + 4 > limit && !fillBuffer(4)) {
1508         throw syntaxError("Unterminated escape sequence");
1509       }
1510       // Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16);
1511       char result = 0;
1512       for (int i = pos, end = i + 4; i < end; i++) {
1513         char c = buffer[i];
1514         result <<= 4;
1515         if (c >= '0' && c <= '9') {
1516           result += (c - '0');
1517         } else if (c >= 'a' && c <= 'f') {
1518           result += (c - 'a' + 10);
1519         } else if (c >= 'A' && c <= 'F') {
1520           result += (c - 'A' + 10);
1521         } else {
1522           throw new NumberFormatException("\\u" + new String(buffer, pos, 4));
1523         }
1524       }
1525       pos += 4;
1526       return result;
1527
1528     case 't':
1529       return '\t';
1530
1531     case 'b':
1532       return '\b';
1533
1534     case 'n':
1535       return '\n';
1536
1537     case 'r':
1538       return '\r';
1539
1540     case 'f':
1541       return '\f';
1542
1543     case '\n':
1544       lineNumber++;
1545       lineStart = pos;
1546       // fall-through
1547
1548     case '\'':
1549     case '"':
1550     case '\\':
1551     case '/':    
1552         return escaped;
1553     default:
1554         // throw error when none of the above cases are matched
1555         throw syntaxError("Invalid escape sequence");
1556     }
1557   }
1558
1559   /**
1560    * Throws a new IO exception with the given message and a context snippet
1561    * with this reader's content.
1562    */

1563   private IOException syntaxError(String message) throws IOException {
1564     throw new MalformedJsonException(message + locationString());
1565   }
1566
1567   /**
1568    * Consumes the non-execute prefix if it exists.
1569    */

1570   private void consumeNonExecutePrefix() throws IOException {
1571     // fast forward through the leading whitespace
1572     nextNonWhitespace(true);
1573     pos--;
1574
1575     if (pos + NON_EXECUTE_PREFIX.length > limit && !fillBuffer(NON_EXECUTE_PREFIX.length)) {
1576       return;
1577     }
1578
1579     for (int i = 0; i < NON_EXECUTE_PREFIX.length; i++) {
1580       if (buffer[pos + i] != NON_EXECUTE_PREFIX[i]) {
1581         return// not a security token!
1582       }
1583     }
1584
1585     // we consumed a security token!
1586     pos += NON_EXECUTE_PREFIX.length;
1587   }
1588
1589   static {
1590     JsonReaderInternalAccess.INSTANCE = new JsonReaderInternalAccess() {
1591       @Override public void promoteNameToValue(JsonReader reader) throws IOException {
1592         if (reader instanceof JsonTreeReader) {
1593           ((JsonTreeReader)reader).promoteNameToValue();
1594           return;
1595         }
1596         int p = reader.peeked;
1597         if (p == PEEKED_NONE) {
1598           p = reader.doPeek();
1599         }
1600         if (p == PEEKED_DOUBLE_QUOTED_NAME) {
1601           reader.peeked = PEEKED_DOUBLE_QUOTED;
1602         } else if (p == PEEKED_SINGLE_QUOTED_NAME) {
1603           reader.peeked = PEEKED_SINGLE_QUOTED;
1604         } else if (p == PEEKED_UNQUOTED_NAME) {
1605           reader.peeked = PEEKED_UNQUOTED;
1606         } else {
1607           throw new IllegalStateException(
1608               "Expected a name but was " + reader.peek() + reader.locationString());
1609         }
1610       }
1611     };
1612   }
1613 }
1614