15977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot/*
25977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Copyright (C) 2010 The Android Open Source Project
35977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
45977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License");
55977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * you may not use this file except in compliance with the License.
65977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * You may obtain a copy of the License at
75977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
85977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *      http://www.apache.org/licenses/LICENSE-2.0
95977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Unless required by applicable law or agreed to in writing, software
115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS,
125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * See the License for the specific language governing permissions and
145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * limitations under the License.
155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot */
165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotpackage com.android.json.stream;
185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotimport java.io.IOException;
205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotimport java.io.Reader;
215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotimport java.io.Closeable;
225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotimport java.util.ArrayList;
235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotimport java.util.List;
245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot/**
265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * encoded value as a stream of tokens. This stream includes both literal
285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * values (strings, numbers, booleans, and nulls) as well as the begin and
295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * end delimiters of objects and arrays. The tokens are traversed in
305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * depth-first order, the same order that they appear in the JSON document.
315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Within JSON objects, name/value pairs are represented by a single token.
325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <h3>Parsing JSON</h3>
345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * To create a recursive descent parser for your own JSON streams, first create
355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * an entry point method that creates a {@code JsonReader}.
365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <p>Next, create handler methods for each structure in your JSON text. You'll
385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * need a method for each object type and for each array type.
395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <ul>
405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   <li>Within <strong>array handling</strong> methods, first call {@link
415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       #beginArray} to consume the array's opening bracket. Then create a
425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       while loop that accumulates values, terminating when {@link #hasNext}
435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       is false. Finally, read the array's closing bracket by calling {@link
445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       #endArray}.
455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   <li>Within <strong>object handling</strong> methods, first call {@link
465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       #beginObject} to consume the object's opening brace. Then create a
475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       while loop that assigns values to local variables based on their name.
485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       This loop should terminate when {@link #hasNext} is false. Finally,
495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       read the object's closing brace by calling {@link #endObject}.
505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * </ul>
515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <p>When a nested object or array is encountered, delegate to the
525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * corresponding handler method.
535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <p>When an unknown name is encountered, strict parsers should fail with an
555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * exception. Lenient parsers should call {@link #skipValue()} to recursively
565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * skip the value's nested tokens, which may otherwise conflict.
575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <p>If a value may be null, you should first check using {@link #peek()}.
595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Null literals can be consumed using either {@link #nextNull()} or {@link
605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * #skipValue()}.
615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <h3>Example</h3>
635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * Suppose we'd like to parse a stream of messages such as the following: <pre> {@code
645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * [
655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   {
665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "id": 912345678901,
675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "text": "How do I read JSON on Android?",
685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "geo": null,
695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "user": {
705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       "name": "android_newb",
715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       "followers_count": 41
725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *      }
735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   },
745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   {
755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "id": 912345678902,
765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "text": "@android_newb just use android.util.JsonReader!",
775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "geo": [50.454722, -104.606667],
785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     "user": {
795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       "name": "jesse",
805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       "followers_count": 2
815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     }
825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   }
835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * ]}</pre>
845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * This code implements the parser for the above structure: <pre>   {@code
855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   public List<Message> readJsonStream(InputStream in) throws IOException {
875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     return readMessagesArray(reader);
895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   }
905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   public List<Message> readMessagesArray(JsonReader reader) throws IOException {
925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     List<Message> messages = new ArrayList<Message>();
935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.beginArray();
955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     while (reader.hasNext()) {
965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       messages.add(readMessage(reader));
975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     }
985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.endArray();
995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     return messages;
1005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   }
1015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   public Message readMessage(JsonReader reader) throws IOException {
1035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     long id = -1;
1045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     String text = null;
1055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     User user = null;
1065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     List<Double> geo = null;
1075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.beginObject();
1095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     while (reader.hasNext()) {
1105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       String name = reader.nextName();
1115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       if (name.equals("id")) {
1125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         id = reader.nextLong();
1135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       } else if (name.equals("text")) {
1145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         text = reader.nextString();
1155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
1165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         geo = readDoublesArray(reader);
1175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       } else if (name.equals("user")) {
1185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         user = readUser(reader);
1195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       } else {
1205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         reader.skipValue();
1215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       }
1225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     }
1235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.endObject();
1245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     return new Message(id, text, user, geo);
1255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   }
1265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   public List<Double> readDoublesArray(JsonReader reader) throws IOException {
1285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     List<Double> doubles = new ArrayList<Double>();
1295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.beginArray();
1315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     while (reader.hasNext()) {
1325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       doubles.add(reader.nextDouble());
1335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     }
1345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.endArray();
1355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     return doubles;
1365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   }
1375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   public User readUser(JsonReader reader) throws IOException {
1395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     String username = null;
1405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     int followersCount = -1;
1415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.beginObject();
1435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     while (reader.hasNext()) {
1445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       String name = reader.nextName();
1455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       if (name.equals("name")) {
1465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         username = reader.nextString();
1475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       } else if (name.equals("followers_count")) {
1485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         followersCount = reader.nextInt();
1495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       } else {
1505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *         reader.skipValue();
1515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *       }
1525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     }
1535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     reader.endObject();
1545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *     return new User(username, followersCount);
1555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *   }}</pre>
1565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <h3>Number Handling</h3>
1585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * This reader permits numeric values to be read as strings and string values to
1595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * be read as numbers. For example, both elements of the JSON array {@code
1605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}.
1615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * This behavior is intended to prevent lossy numeric conversions: double is
1625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * JavaScript's only numeric type and very large values like {@code
1635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * 9007199254740993} cannot be represented exactly on that platform. To minimize
1645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * precision loss, extremely large values should be written and read as strings
1655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * in JSON.
1665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot *
1675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * <p>Each {@code JsonReader} may be used to read a single JSON stream. Instances
1685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot * of this class are not thread safe.
1695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot */
1705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabotpublic final class JsonReader implements Closeable {
1715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
1725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private static final String TRUE = "true";
1735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private static final String FALSE = "false";
1745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
1755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /** The input JSON. */
1765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private final Reader in;
1775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
1785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /** True to accept non-spec compliant JSON */
1795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private boolean lenient = false;
1805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
1815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
1825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Use a manual buffer to easily read and unread upcoming characters, and
1835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * also so we can create strings without an intermediate StringBuilder.
1845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * We decode literals directly out of this buffer, so it must be at least as
1855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * long as the longest token that can be reported as a number.
1865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
1875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private final char[] buffer = new char[1024];
1885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private int pos = 0;
1895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private int limit = 0;
1905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
1915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private final List<JsonScope> stack = new ArrayList<JsonScope>();
1925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    {
1935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        push(JsonScope.EMPTY_DOCUMENT);
1945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
1955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
1965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
1975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * The type of the next token to be returned by {@link #peek} and {@link
1985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * #advance}. If null, peek() will assign a value.
1995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken token;
2015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /** The text of the next name. */
2035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private String name;
2045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /*
2065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * For the next literal value, we may have the text value, or the position
2075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * and length in the buffer.
2085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private String value;
2105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private int valuePos;
2115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private int valueLength;
2125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /** True if we're currently handling a skipValue() call. */
2145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private boolean skipping = false;
2155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Creates a new instance that reads a JSON-encoded stream from {@code in}.
2185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public JsonReader(Reader in) {
2205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (in == null) {
2215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new NullPointerException("in == null");
2225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
2235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        this.in = in;
2245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Configure this parser to be  be liberal in what it accepts. By default,
2285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * this parser is strict and only accepts JSON as specified by <a
2295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the
2305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * parser to lenient causes it to ignore the following syntax errors:
2315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
2325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * <ul>
2335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>End of line comments starting with {@code //} or {@code #} and
2345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *       ending with a newline character.
2355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>C-style comments starting with {@code /*} and ending with
2365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *       {@code *}{@code /}. Such comments may not be nested.
2375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>Names that are unquoted or {@code 'single quoted'}.
2385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>Strings that are unquoted or {@code 'single quoted'}.
2395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>Array elements separated by {@code ;} instead of {@code ,}.
2405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>Unnecessary array separators. These are interpreted as if null
2415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *       was the omitted value.
2425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>Names and values separated by {@code =} or {@code =>} instead of
2435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *       {@code :}.
2445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *   <li>Name/value pairs separated by {@code ;} instead of {@code ,}.
2455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * </ul>
2465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void setLenient(boolean lenient) {
2485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        this.lenient = lenient;
2495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Consumes the next token from the JSON stream and asserts that it is the
2535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * beginning of a new array.
2545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void beginArray() throws IOException {
2565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        expect(JsonToken.BEGIN_ARRAY);
2575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Consumes the next token from the JSON stream and asserts that it is the
2615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * end of the current array.
2625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void endArray() throws IOException {
2645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        expect(JsonToken.END_ARRAY);
2655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Consumes the next token from the JSON stream and asserts that it is the
2695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * beginning of a new object.
2705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void beginObject() throws IOException {
2725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        expect(JsonToken.BEGIN_OBJECT);
2735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Consumes the next token from the JSON stream and asserts that it is the
2775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * end of the current array.
2785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void endObject() throws IOException {
2805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        expect(JsonToken.END_OBJECT);
2815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Consumes {@code expected}.
2855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private void expect(JsonToken expected) throws IOException {
2875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
2885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != expected) {
2895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected " + expected + " but was " + peek());
2905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
2915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
2925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
2935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
2945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
2955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns true if the current array or object has another element.
2965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
2975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public boolean hasNext() throws IOException {
2985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
2995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
3005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
3015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
3035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the type of the next token without consuming it.
3045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
3055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public JsonToken peek() throws IOException {
3065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != null) {
3075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot          return token;
3085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
3095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        switch (peekStack()) {
3115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case EMPTY_DOCUMENT:
3125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                replaceTop(JsonScope.NONEMPTY_DOCUMENT);
3135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                JsonToken firstToken = nextValue();
3145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
3155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    throw new IOException(
3165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            "Expected JSON document to start with '[' or '{' but was " + token);
3175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
3185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return firstToken;
3195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case EMPTY_ARRAY:
3205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return nextInArray(true);
3215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case NONEMPTY_ARRAY:
3225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return nextInArray(false);
3235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case EMPTY_OBJECT:
3245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return nextInObject(true);
3255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case DANGLING_NAME:
3265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return objectValue();
3275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case NONEMPTY_OBJECT:
3285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return nextInObject(false);
3295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case NONEMPTY_DOCUMENT:
3305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return token = JsonToken.END_DOCUMENT;
3315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case CLOSED:
3325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                throw new IllegalStateException("JsonReader is closed");
3335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            default:
3345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                throw new AssertionError();
3355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
3365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
3375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
3395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Advances the cursor in the JSON stream to the next token.
3405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
3415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken advance() throws IOException {
3425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
3435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        JsonToken result = token;
3455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        token = null;
3465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        value = null;
3475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        name = null;
3485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
3495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
3505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
3525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the next token, a {@link JsonToken#NAME property name}, and
3535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * consumes it.
3545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
3555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IOException if the next token in the stream is not a property
3565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     name.
3575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
3585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public String nextName() throws IOException {
3595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
3605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.NAME) {
3615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected a name but was " + peek());
3625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
3635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        String result = name;
3645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
3655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
3665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
3675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
3695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the {@link JsonToken#STRING string} value of the next token,
3705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * consuming it. If the next token is a number, this method will return its
3715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * string form.
3725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
3735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IllegalStateException if the next token is not a string or if
3745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     this reader is closed.
3755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
3765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public String nextString() throws IOException {
3775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
3785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
3795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected a string but was " + peek());
3805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
3815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        String result = value;
3835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
3845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
3855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
3865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
3875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
3885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the {@link JsonToken#BOOLEAN boolean} value of the next token,
3895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * consuming it.
3905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
3915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IllegalStateException if the next token is not a boolean or if
3925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     this reader is closed.
3935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
3945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public boolean nextBoolean() throws IOException {
3955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
3965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.BOOLEAN) {
3975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected a boolean but was " + token);
3985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
3995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        boolean result = (value == TRUE);
4015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
4025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
4035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
4045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
4065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Consumes the next token from the JSON stream and asserts that it is a
4075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * literal null.
4085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
4095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IllegalStateException if the next token is not null or if this
4105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     reader is closed.
4115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
4125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void nextNull() throws IOException {
4135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
4145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.NULL) {
4155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected null but was " + token);
4165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
4175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
4195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
4205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
4225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the {@link JsonToken#NUMBER double} value of the next token,
4235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * consuming it. If the next token is a string, this method will attempt to
4245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * parse it as a double using {@link Double#parseDouble(String)}.
4255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
4265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IllegalStateException if the next token is not a literal value.
4275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
4285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public double nextDouble() throws IOException {
4295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
4305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
4315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected a double but was " + token);
4325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
4335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        double result = Double.parseDouble(value);
4355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
4365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
4375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
4385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
4405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the {@link JsonToken#NUMBER long} value of the next token,
4415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * consuming it. If the next token is a string, this method will attempt to
4425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * parse it as a long. If the next token's numeric value cannot be exactly
4435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * represented by a Java {@code long}, this method throws.
4445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
4455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IllegalStateException if the next token is not a literal value.
4465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws NumberFormatException if the next literal value cannot be parsed
4475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     as a number, or exactly represented as a long.
4485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
4495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public long nextLong() throws IOException {
4505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
4515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
4525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected a long but was " + token);
4535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
4545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        long result;
4565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        try {
4575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = Long.parseLong(value);
4585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } catch (NumberFormatException ignored) {
4595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
4605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = (long) asDouble;
4615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if ((double) result != asDouble) {
4625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                throw new NumberFormatException(value);
4635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
4645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
4655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
4675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
4685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
4695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
4715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the {@link JsonToken#NUMBER int} value of the next token,
4725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * consuming it. If the next token is a string, this method will attempt to
4735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * parse it as an int. If the next token's numeric value cannot be exactly
4745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * represented by a Java {@code int}, this method throws.
4755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
4765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws IllegalStateException if the next token is not a literal value.
4775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws NumberFormatException if the next literal value cannot be parsed
4785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     as a number, or exactly represented as an int.
4795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
4805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public int nextInt() throws IOException {
4815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        peek();
4825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
4835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw new IllegalStateException("Expected an int but was " + token);
4845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
4855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int result;
4875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        try {
4885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = Integer.parseInt(value);
4895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } catch (NumberFormatException ignored) {
4905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
4915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = (int) asDouble;
4925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if ((double) result != asDouble) {
4935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                throw new NumberFormatException(value);
4945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
4955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
4965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
4975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        advance();
4985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
4995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
5025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Closes this JSON reader and the underlying {@link Reader}.
5035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
5045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void close() throws IOException {
5055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        value = null;
5065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        token = null;
5075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        stack.clear();
5085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        stack.add(JsonScope.CLOSED);
5095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        in.close();
5105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
5135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Skips the next value recursively. If it is an object or array, all nested
5145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * elements are skipped. This method is intended for use when the JSON token
5155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * stream contains unrecognized or unhandled values.
5165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
5175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public void skipValue() throws IOException {
5185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        skipping = true;
5195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        try {
5205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            int count = 0;
5215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            do {
5225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                JsonToken token = advance();
5235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (token == JsonToken.BEGIN_ARRAY || token == JsonToken.BEGIN_OBJECT) {
5245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    count++;
5255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                } else if (token == JsonToken.END_ARRAY || token == JsonToken.END_OBJECT) {
5265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    count--;
5275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
5285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            } while (count != 0);
5295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } finally {
5305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            skipping = false;
5315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
5325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonScope peekStack() {
5355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return stack.get(stack.size() - 1);
5365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonScope pop() {
5395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return stack.remove(stack.size() - 1);
5405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private void push(JsonScope newTop) {
5435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        stack.add(newTop);
5445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
5475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Replace the value on the top of the stack with the given value.
5485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
5495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private void replaceTop(JsonScope newTop) {
5505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        stack.set(stack.size() - 1, newTop);
5515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken nextInArray(boolean firstElement) throws IOException {
5545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (firstElement) {
5555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            replaceTop(JsonScope.NONEMPTY_ARRAY);
5565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
5575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            /* Look for a comma before each element after the first element. */
5585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            switch (nextNonWhitespace()) {
5595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ']':
5605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    pop();
5615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    return token = JsonToken.END_ARRAY;
5625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ';':
5635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    checkLenient(); // fall-through
5645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ',':
5655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    break;
5665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                default:
5675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    throw syntaxError("Unterminated array");
5685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
5695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
5705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        switch (nextNonWhitespace()) {
5725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case ']':
5735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (firstElement) {
5745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    pop();
5755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    return token = JsonToken.END_ARRAY;
5765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
5775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                // fall-through to handle ",]"
5785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case ';':
5795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case ',':
5805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                /* In lenient mode, a 0-length literal means 'null' */
5815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                checkLenient();
5825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                pos--;
5835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                value = "null";
5845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return token = JsonToken.NULL;
5855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            default:
5865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                pos--;
5875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return nextValue();
5885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
5895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
5905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
5915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken nextInObject(boolean firstElement) throws IOException {
5925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        /*
5935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         * Read delimiters. Either a comma/semicolon separating this and the
5945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         * previous name-value pair, or a close brace to denote the end of the
5955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         * object.
5965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         */
5975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (firstElement) {
5985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            /* Peek to see if this is the empty object. */
5995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            switch (nextNonWhitespace()) {
6005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '}':
6015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    pop();
6025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    return token = JsonToken.END_OBJECT;
6035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                default:
6045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    pos--;
6055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
6065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
6075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            switch (nextNonWhitespace()) {
6085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '}':
6095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    pop();
6105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    return token = JsonToken.END_OBJECT;
6115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ';':
6125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ',':
6135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    break;
6145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                default:
6155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    throw syntaxError("Unterminated object");
6165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
6175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
6185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        /* Read the name. */
6205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int quote = nextNonWhitespace();
6215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        switch (quote) {
6225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '\'':
6235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                checkLenient(); // fall-through
6245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '"':
6255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                name = nextString((char) quote);
6265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                break;
6275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            default:
6285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                checkLenient();
6295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                pos--;
6305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                name = nextLiteral(false);
6315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (name.isEmpty()) {
6325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    throw syntaxError("Expected name");
6335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
6345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
6355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        replaceTop(JsonScope.DANGLING_NAME);
6375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return token = JsonToken.NAME;
6385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
6395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken objectValue() throws IOException {
6415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        /*
6425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         * Read the name/value separator. Usually a colon ':'. In lenient mode
6435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         * we also accept an equals sign '=', or an arrow "=>".
6445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot         */
6455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        switch (nextNonWhitespace()) {
6465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case ':':
6475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                break;
6485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '=':
6495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                checkLenient();
6505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
6515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    pos++;
6525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
6535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                break;
6545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            default:
6555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                throw syntaxError("Expected ':'");
6565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
6575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        replaceTop(JsonScope.NONEMPTY_OBJECT);
6595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return nextValue();
6605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
6615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken nextValue() throws IOException {
6635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int c = nextNonWhitespace();
6645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        switch (c) {
6655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '{':
6665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                push(JsonScope.EMPTY_OBJECT);
6675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return token = JsonToken.BEGIN_OBJECT;
6685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '[':
6705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                push(JsonScope.EMPTY_ARRAY);
6715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return token = JsonToken.BEGIN_ARRAY;
6725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '\'':
6745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                checkLenient(); // fall-through
6755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '"':
6765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                value = nextString((char) c);
6775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return token = JsonToken.STRING;
6785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            default:
6805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                pos--;
6815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return readLiteral();
6825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
6835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
6845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
6865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns true once {@code limit - pos >= minimum}. If the data is
6875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * exhausted before that many characters are available, this returns
6885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * false.
6895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
6905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private boolean fillBuffer(int minimum) throws IOException {
6915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (limit != pos) {
6925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            limit -= pos;
6935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            System.arraycopy(buffer, pos, buffer, 0, limit);
6945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
6955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            limit = 0;
6965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
6975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
6985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        pos = 0;
6995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int total;
7005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) {
7015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            limit += total;
7025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (limit >= minimum) {
7035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return true;
7045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
7055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
7065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return false;
7075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
7085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private int nextNonWhitespace() throws IOException {
7105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        while (pos < limit || fillBuffer(1)) {
7115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            int c = buffer[pos++];
7125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            switch (c) {
7135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\t':
7145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ' ':
7155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\n':
7165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\r':
7175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    continue;
7185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '/':
7205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    if (pos == limit && !fillBuffer(1)) {
7215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        return c;
7225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    }
7235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    checkLenient();
7255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    char peek = buffer[pos];
7265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    switch (peek) {
7275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        case '*':
7285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            // skip a /* c-style comment */
7295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            pos++;
7305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            if (!skipTo("*/")) {
7315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                                throw syntaxError("Unterminated comment");
7325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            }
7335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            pos += 2;
7345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            continue;
7355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        case '/':
7375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            // skip a // end-of-line comment
7385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            pos++;
7395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            skipToEndOfLine();
7405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            continue;
7415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        default:
7435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                            return c;
7445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    }
7455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '#':
7475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    /*
7485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                     * Skip a # hash end-of-line comment. The JSON RFC doesn't
7495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                     * specify this behaviour, but it's required to parse
7505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                     * existing documents. See http://b/2571423.
7515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                     */
7525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    checkLenient();
7535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    skipToEndOfLine();
7545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    continue;
7555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                default:
7575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    return c;
7585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
7595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
7605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        throw syntaxError("End of input");
7625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
7635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private void checkLenient() throws IOException {
7655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (!lenient) {
7665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON");
7675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
7685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
7695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
7715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Advances the position until after the next newline character. If the line
7725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
7735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * caller.
7745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
7755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private void skipToEndOfLine() throws IOException {
7765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        while (pos < limit || fillBuffer(1)) {
7775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            char c = buffer[pos++];
7785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (c == '\r' || c == '\n') {
7795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                break;
7805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
7815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
7825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
7835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private boolean skipTo(String toFind) throws IOException {
7855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        outer:
7865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        for (; pos + toFind.length() < limit || fillBuffer(toFind.length()); pos++) {
7875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            for (int c = 0; c < toFind.length(); c++) {
7885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (buffer[pos + c] != toFind.charAt(c)) {
7895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    continue outer;
7905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
7915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
7925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return true;
7935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
7945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return false;
7955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
7965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
7975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
7985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Returns the string up to but not including {@code quote}, unescaping any
7995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * character escape sequences encountered along the way. The opening quote
8005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * should have already been read. This consumes the closing quote, but does
8015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * not include it in the returned string.
8025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
8035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @param quote either ' or ".
8045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws NumberFormatException if any unicode escape sequences are
8055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     malformed.
8065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
8075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private String nextString(char quote) throws IOException {
8085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        StringBuilder builder = null;
8095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        do {
8105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            /* the index of the first character not yet appended to the builder. */
8115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            int start = pos;
8125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            while (pos < limit) {
8135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                int c = buffer[pos++];
8145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (c == quote) {
8165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    if (skipping) {
8175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        return "skipped!";
8185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    } else if (builder == null) {
8195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        return new String(buffer, start, pos - start - 1);
8205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    } else {
8215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        builder.append(buffer, start, pos - start - 1);
8225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        return builder.toString();
8235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    }
8245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                } else if (c == '\\') {
8265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    if (builder == null) {
8275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                        builder = new StringBuilder();
8285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    }
8295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    builder.append(buffer, start, pos - start - 1);
8305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    builder.append(readEscapeCharacter());
8315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    start = pos;
8325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
8335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
8345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (builder == null) {
8365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                builder = new StringBuilder();
8375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
8385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            builder.append(buffer, start, pos - start);
8395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } while (fillBuffer(1));
8405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        throw syntaxError("Unterminated string");
8425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
8435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
8455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Reads the value up to but not including any delimiter characters. This
8465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * does not consume the delimiter character.
8475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
8485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @param assignOffsetsOnly true for this method to only set the valuePos
8495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     and valueLength fields and return a null result. This only works if
8505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     the literal is short; a string is returned otherwise.
8515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
8525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private String nextLiteral(boolean assignOffsetsOnly) throws IOException {
8535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        StringBuilder builder = null;
8545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        valuePos = -1;
8555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        valueLength = 0;
8565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int i = 0;
8575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        findNonLiteralCharacter:
8595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        while (true) {
8605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            for (; pos + i < limit; i++) {
8615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                switch (buffer[pos + i]) {
8625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '/':
8635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\\':
8645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ';':
8655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '#':
8665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '=':
8675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    checkLenient(); // fall-through
8685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '{':
8695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '}':
8705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '[':
8715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ']':
8725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ':':
8735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ',':
8745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case ' ':
8755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\t':
8765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\f':
8775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\r':
8785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                case '\n':
8795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    break findNonLiteralCharacter;
8805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
8815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
8825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            /*
8845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot             * Attempt to load the entire literal into the buffer at once. If
8855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot             * we run out of input, add a non-literal character at the end so
8865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot             * that decoding doesn't need to do bounds checks.
8875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot             */
8885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (i < buffer.length) {
8895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (fillBuffer(i + 1)) {
8905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    continue;
8915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                } else {
8925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    buffer[limit] = '\0';
8935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    break;
8945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
8955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
8965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
8975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            // use a StringBuilder when the value is too long. It must be an unquoted string.
8985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (builder == null) {
8995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                builder = new StringBuilder();
9005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
9015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            builder.append(buffer, pos, i);
9025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            valueLength += i;
9035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            pos += i;
9045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            i = 0;
9055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (!fillBuffer(1)) {
9065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                break;
9075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
9085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
9095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        String result;
9115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (assignOffsetsOnly && builder == null) {
9125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            valuePos = pos;
9135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = null;
9145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else if (skipping) {
9155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = "skipped!";
9165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else if (builder == null) {
9175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = new String(buffer, pos, i);
9185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
9195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            builder.append(buffer, pos, i);
9205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            result = builder.toString();
9215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
9225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        valueLength += i;
9235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        pos += i;
9245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return result;
9255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
9265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    @Override public String toString() {
9285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return getClass().getSimpleName() + " near " + getSnippet();
9295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
9305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
9325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Unescapes the character identified by the character or characters that
9335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * immediately follow a backslash. The backslash '\' should have already
9345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * been read. This supports both unicode escapes "u000A" and two-character
9355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * escapes "\n".
9365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
9375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * @throws NumberFormatException if any unicode escape sequences are
9385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *     malformed.
9395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
9405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private char readEscapeCharacter() throws IOException {
9415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (pos == limit && !fillBuffer(1)) {
9425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw syntaxError("Unterminated escape sequence");
9435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
9445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        char escaped = buffer[pos++];
9465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        switch (escaped) {
9475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case 'u':
9485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                if (pos + 4 > limit && !fillBuffer(4)) {
9495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    throw syntaxError("Unterminated escape sequence");
9505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
9515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                String hex = new String(buffer, pos, 4);
9525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                pos += 4;
9535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return (char) Integer.parseInt(hex, 16);
9545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case 't':
9565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return '\t';
9575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case 'b':
9595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return '\b';
9605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case 'n':
9625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return '\n';
9635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case 'r':
9655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return '\r';
9665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case 'f':
9685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return '\f';
9695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '\'':
9715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '"':
9725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            case '\\':
9735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            default:
9745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return escaped;
9755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
9765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
9775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
9795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Reads a null, boolean, numeric or unquoted string literal value.
9805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
9815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken readLiteral() throws IOException {
9825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        value = nextLiteral(true);
9835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (valueLength == 0) {
9845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            throw syntaxError("Expected literal value");
9855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
9865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        token = decodeLiteral();
9875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (token == JsonToken.STRING) {
9885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot          checkLenient();
9895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
9905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return token;
9915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
9925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
9935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
9945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Assigns {@code nextToken} based on the value of {@code nextValue}.
9955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
9965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken decodeLiteral() throws IOException {
9975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (valuePos == -1) {
9985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            // it was too long to fit in the buffer so it can only be a string
9995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.STRING;
10005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else if (valueLength == 4
10015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('n' == buffer[valuePos    ] || 'N' == buffer[valuePos    ])
10025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('u' == buffer[valuePos + 1] || 'U' == buffer[valuePos + 1])
10035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])
10045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('l' == buffer[valuePos + 3] || 'L' == buffer[valuePos + 3])) {
10055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            value = "null";
10065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.NULL;
10075977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else if (valueLength == 4
10085977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('t' == buffer[valuePos    ] || 'T' == buffer[valuePos    ])
10095977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('r' == buffer[valuePos + 1] || 'R' == buffer[valuePos + 1])
10105977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('u' == buffer[valuePos + 2] || 'U' == buffer[valuePos + 2])
10115977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('e' == buffer[valuePos + 3] || 'E' == buffer[valuePos + 3])) {
10125977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            value = TRUE;
10135977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.BOOLEAN;
10145977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else if (valueLength == 5
10155977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('f' == buffer[valuePos    ] || 'F' == buffer[valuePos    ])
10165977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('a' == buffer[valuePos + 1] || 'A' == buffer[valuePos + 1])
10175977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])
10185977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('s' == buffer[valuePos + 3] || 'S' == buffer[valuePos + 3])
10195977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                && ('e' == buffer[valuePos + 4] || 'E' == buffer[valuePos + 4])) {
10205977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            value = FALSE;
10215977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.BOOLEAN;
10225977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
10235977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            value = new String(buffer, valuePos, valueLength);
10245977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return decodeNumber(buffer, valuePos, valueLength);
10255977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
10265977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
10275977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10285977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
10295977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Determine whether the characters is a JSON number. Numbers are of the
10305977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * form -12.34e+56. Fractional and exponential parts are optional. Leading
10315977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * zeroes are not allowed in the value or exponential part, but are allowed
10325977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * in the fraction.
10335977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     *
10345977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * <p>This has a side effect of setting isInteger.
10355977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
10365977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private JsonToken decodeNumber(char[] chars, int offset, int length) {
10375977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int i = offset;
10385977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int c = chars[i];
10395977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10405977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (c == '-') {
10415977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            c = chars[++i];
10425977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
10435977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10445977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (c == '0') {
10455977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            c = chars[++i];
10465977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else if (c >= '1' && c <= '9') {
10475977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            c = chars[++i];
10485977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            while (c >= '0' && c <= '9') {
10495977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                c = chars[++i];
10505977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
10515977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
10525977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.STRING;
10535977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
10545977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10555977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (c == '.') {
10565977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            c = chars[++i];
10575977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            while (c >= '0' && c <= '9') {
10585977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                c = chars[++i];
10595977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
10605977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
10615977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10625977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (c == 'e' || c == 'E') {
10635977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            c = chars[++i];
10645977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (c == '+' || c == '-') {
10655977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                c = chars[++i];
10665977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
10675977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            if (c >= '0' && c <= '9') {
10685977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                c = chars[++i];
10695977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                while (c >= '0' && c <= '9') {
10705977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                    c = chars[++i];
10715977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                }
10725977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            } else {
10735977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot                return JsonToken.STRING;
10745977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            }
10755977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
10765977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10775977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        if (i == offset + length) {
10785977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.NUMBER;
10795977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        } else {
10805977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            return JsonToken.STRING;
10815977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
10825977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
10835977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10845977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    /**
10855977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * Throws a new IO exception with the given message and a context snippet
10865977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     * with this reader's content.
10875977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot     */
10885977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    public IOException syntaxError(String message) throws IOException {
10895977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        throw new JsonSyntaxException(message + " near " + getSnippet());
10905977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
10915977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
10925977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private CharSequence getSnippet() {
10935977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        StringBuilder snippet = new StringBuilder();
10945977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int beforePos = Math.min(pos, 20);
10955977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        snippet.append(buffer, pos - beforePos, beforePos);
10965977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        int afterPos = Math.min(limit - pos, 20);
10975977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        snippet.append(buffer, pos, afterPos);
10985977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        return snippet;
10995977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
11005977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot
11015977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    private static class JsonSyntaxException extends IOException {
11025977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        private JsonSyntaxException(String s) {
11035977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot            super(s);
11045977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot        }
11055977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot    }
11065977e94bfe57100042cdf41e476d7cb971137e5fBrett Chabot}
1107