176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson/*
276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * you may not use this file except in compliance with the License.
676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * You may obtain a copy of the License at
776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
1076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Unless required by applicable law or agreed to in writing, software
1176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * See the License for the specific language governing permissions and
1476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * limitations under the License.
1576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson */
1676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
1776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilsonpackage android.util;
1876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
19847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilsonimport java.io.Closeable;
20eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilsonimport java.io.EOFException;
2176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilsonimport java.io.IOException;
2276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilsonimport java.io.Reader;
2376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilsonimport java.util.ArrayList;
2476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilsonimport java.util.List;
25847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilsonimport libcore.internal.StringPool;
2676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
2776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson/**
2876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
2976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * encoded value as a stream of tokens. This stream includes both literal
3076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * values (strings, numbers, booleans, and nulls) as well as the begin and
3176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * end delimiters of objects and arrays. The tokens are traversed in
3276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * depth-first order, the same order that they appear in the JSON document.
3376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Within JSON objects, name/value pairs are represented by a single token.
3476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
3576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <h3>Parsing JSON</h3>
363312b297600ec97f28f979dfbdf6c95e164a304fJesse Wilson * To create a recursive descent parser for your own JSON streams, first create
373312b297600ec97f28f979dfbdf6c95e164a304fJesse Wilson * an entry point method that creates a {@code JsonReader}.
3876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
3976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <p>Next, create handler methods for each structure in your JSON text. You'll
4076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * need a method for each object type and for each array type.
4176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <ul>
4276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   <li>Within <strong>array handling</strong> methods, first call {@link
4376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       #beginArray} to consume the array's opening bracket. Then create a
4476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       while loop that accumulates values, terminating when {@link #hasNext}
4576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       is false. Finally, read the array's closing bracket by calling {@link
4676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       #endArray}.
4776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   <li>Within <strong>object handling</strong> methods, first call {@link
4876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       #beginObject} to consume the object's opening brace. Then create a
4976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       while loop that assigns values to local variables based on their name.
5076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       This loop should terminate when {@link #hasNext} is false. Finally,
5176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       read the object's closing brace by calling {@link #endObject}.
5276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * </ul>
5376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <p>When a nested object or array is encountered, delegate to the
5476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * corresponding handler method.
5576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
5676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <p>When an unknown name is encountered, strict parsers should fail with an
5776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * exception. Lenient parsers should call {@link #skipValue()} to recursively
5876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * skip the value's nested tokens, which may otherwise conflict.
5976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
6076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <p>If a value may be null, you should first check using {@link #peek()}.
6176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Null literals can be consumed using either {@link #nextNull()} or {@link
6276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * #skipValue()}.
6376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
6476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <h3>Example</h3>
6576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * Suppose we'd like to parse a stream of messages such as the following: <pre> {@code
6676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * [
6776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   {
6876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "id": 912345678901,
6976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "text": "How do I read JSON on Android?",
7076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "geo": null,
7176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "user": {
7276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       "name": "android_newb",
7376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       "followers_count": 41
7476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *      }
7576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   },
7676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   {
7776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "id": 912345678902,
7876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "text": "@android_newb just use android.util.JsonReader!",
7976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "geo": [50.454722, -104.606667],
8076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     "user": {
8176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       "name": "jesse",
8276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       "followers_count": 2
8376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     }
8476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   }
8576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * ]}</pre>
8676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * This code implements the parser for the above structure: <pre>   {@code
8776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
8876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   public List<Message> readJsonStream(InputStream in) throws IOException {
8976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
909d30ea033329f76ea9b20fa778f04cddd8fe710cJesse Wilson *     try {
919d30ea033329f76ea9b20fa778f04cddd8fe710cJesse Wilson *       return readMessagesArray(reader);
929d30ea033329f76ea9b20fa778f04cddd8fe710cJesse Wilson *     } finally {
939d30ea033329f76ea9b20fa778f04cddd8fe710cJesse Wilson *       reader.close();
949d30ea033329f76ea9b20fa778f04cddd8fe710cJesse Wilson *     }
9576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   }
9676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
9776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   public List<Message> readMessagesArray(JsonReader reader) throws IOException {
9876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     List<Message> messages = new ArrayList<Message>();
9976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
10076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.beginArray();
10176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     while (reader.hasNext()) {
10276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       messages.add(readMessage(reader));
10376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     }
10476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.endArray();
10576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     return messages;
10676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   }
10776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
10876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   public Message readMessage(JsonReader reader) throws IOException {
10976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     long id = -1;
11076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     String text = null;
11176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     User user = null;
11276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     List<Double> geo = null;
11376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
11476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.beginObject();
11576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     while (reader.hasNext()) {
11676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       String name = reader.nextName();
11776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       if (name.equals("id")) {
11876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         id = reader.nextLong();
11976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       } else if (name.equals("text")) {
12076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         text = reader.nextString();
12176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
12276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         geo = readDoublesArray(reader);
12376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       } else if (name.equals("user")) {
12476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         user = readUser(reader);
12576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       } else {
12676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         reader.skipValue();
12776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       }
12876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     }
12976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.endObject();
13076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     return new Message(id, text, user, geo);
13176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   }
13276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
13376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   public List<Double> readDoublesArray(JsonReader reader) throws IOException {
13476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     List<Double> doubles = new ArrayList<Double>();
13576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
13676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.beginArray();
13776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     while (reader.hasNext()) {
13876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       doubles.add(reader.nextDouble());
13976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     }
14076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.endArray();
14176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     return doubles;
14276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   }
14376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
14476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   public User readUser(JsonReader reader) throws IOException {
14576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     String username = null;
14676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     int followersCount = -1;
14776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
14876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.beginObject();
14976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     while (reader.hasNext()) {
15076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       String name = reader.nextName();
15176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       if (name.equals("name")) {
15276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         username = reader.nextString();
15376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       } else if (name.equals("followers_count")) {
15476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         followersCount = reader.nextInt();
15576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       } else {
15676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *         reader.skipValue();
15776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *       }
15876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     }
15976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     reader.endObject();
16076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *     return new User(username, followersCount);
16176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *   }}</pre>
16276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
16376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <h3>Number Handling</h3>
16476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * This reader permits numeric values to be read as strings and string values to
16576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * be read as numbers. For example, both elements of the JSON array {@code
16676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}.
16776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * This behavior is intended to prevent lossy numeric conversions: double is
16876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * JavaScript's only numeric type and very large values like {@code
16976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * 9007199254740993} cannot be represented exactly on that platform. To minimize
17076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * precision loss, extremely large values should be written and read as strings
17176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * in JSON.
17276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson *
17376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * <p>Each {@code JsonReader} may be used to read a single JSON stream. Instances
17476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson * of this class are not thread safe.
17576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson */
17676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilsonpublic final class JsonReader implements Closeable {
17776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
1789d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private static final String TRUE = "true";
1799d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private static final String FALSE = "false";
1809d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
181847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilson    private final StringPool stringPool = new StringPool();
182847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilson
18376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /** The input JSON. */
18476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private final Reader in;
18576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
1861ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    /** True to accept non-spec compliant JSON */
1871ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    private boolean lenient = false;
1881ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson
18976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
19076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Use a manual buffer to easily read and unread upcoming characters, and
19176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * also so we can create strings without an intermediate StringBuilder.
1929d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * We decode literals directly out of this buffer, so it must be at least as
1939d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * long as the longest token that can be reported as a number.
19476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
19576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private final char[] buffer = new char[1024];
19676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private int pos = 0;
19776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private int limit = 0;
19876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
199febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    /*
200febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson     * The offset of the first character in the buffer.
201febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson     */
202febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    private int bufferStartLine = 1;
203febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    private int bufferStartColumn = 1;
204febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson
20576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private final List<JsonScope> stack = new ArrayList<JsonScope>();
20676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    {
20776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        push(JsonScope.EMPTY_DOCUMENT);
20876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
20976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
21076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
21176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * The type of the next token to be returned by {@link #peek} and {@link
2129d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * #advance}. If null, peek() will assign a value.
21376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
21476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken token;
21576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
21676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /** The text of the next name. */
21776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private String name;
21876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
2199d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    /*
2209d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * For the next literal value, we may have the text value, or the position
2219d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * and length in the buffer.
2229d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     */
22376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private String value;
2249d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private int valuePos;
2259d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private int valueLength;
22676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
227d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson    /** True if we're currently handling a skipValue() call. */
228d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson    private boolean skipping = false;
229d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson
23076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
23176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Creates a new instance that reads a JSON-encoded stream from {@code in}.
23276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
23376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public JsonReader(Reader in) {
23476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        if (in == null) {
23576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            throw new NullPointerException("in == null");
23676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
23776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        this.in = in;
23876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
23976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
24076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
2411ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * Configure this parser to be  be liberal in what it accepts. By default,
2421ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * this parser is strict and only accepts JSON as specified by <a
2431ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the
2441ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * parser to lenient causes it to ignore the following syntax errors:
2451ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *
2461ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * <ul>
2471ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>End of line comments starting with {@code //} or {@code #} and
2481ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *       ending with a newline character.
2491ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>C-style comments starting with {@code /*} and ending with
2501ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *       {@code *}{@code /}. Such comments may not be nested.
2511ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>Names that are unquoted or {@code 'single quoted'}.
2521ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>Strings that are unquoted or {@code 'single quoted'}.
2531ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>Array elements separated by {@code ;} instead of {@code ,}.
2541ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>Unnecessary array separators. These are interpreted as if null
2551ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *       was the omitted value.
2561ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>Names and values separated by {@code =} or {@code =>} instead of
2571ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *       {@code :}.
2581ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     *   <li>Name/value pairs separated by {@code ;} instead of {@code ,}.
2591ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * </ul>
2601ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     */
2611ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    public void setLenient(boolean lenient) {
2621ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        this.lenient = lenient;
2631ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    }
2641ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson
2651ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    /**
266eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson     * Returns true if this parser is liberal in what it accepts.
267eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson     */
268eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson    public boolean isLenient() {
269eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson        return lenient;
270eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson    }
271eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson
272eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson    /**
27376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Consumes the next token from the JSON stream and asserts that it is the
27476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * beginning of a new array.
27576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
27676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void beginArray() throws IOException {
27776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        expect(JsonToken.BEGIN_ARRAY);
27876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
27976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
28076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
28176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Consumes the next token from the JSON stream and asserts that it is the
28276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * end of the current array.
28376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
28476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void endArray() throws IOException {
28576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        expect(JsonToken.END_ARRAY);
28676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
28776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
28876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
28976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Consumes the next token from the JSON stream and asserts that it is the
29076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * beginning of a new object.
29176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
29276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void beginObject() throws IOException {
29376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        expect(JsonToken.BEGIN_OBJECT);
29476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
29576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
29676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
29776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Consumes the next token from the JSON stream and asserts that it is the
29876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * end of the current array.
29976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
30076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void endObject() throws IOException {
30176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        expect(JsonToken.END_OBJECT);
30276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
30376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
30476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
3051ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson     * Consumes {@code expected}.
30676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
3071ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    private void expect(JsonToken expected) throws IOException {
3089d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
3091ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        if (token != expected) {
3101ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            throw new IllegalStateException("Expected " + expected + " but was " + peek());
31176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
31276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
31376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
31476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
31576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
31676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns true if the current array or object has another element.
31776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
31876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public boolean hasNext() throws IOException {
3199d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
3201ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
32176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
32276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
32376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
32476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the type of the next token without consuming it.
32576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
32676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public JsonToken peek() throws IOException {
3279d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != null) {
3289d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson          return token;
32976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
33076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
33176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        switch (peekStack()) {
33276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case EMPTY_DOCUMENT:
33376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                replaceTop(JsonScope.NONEMPTY_DOCUMENT);
33476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                JsonToken firstToken = nextValue();
335eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
33676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    throw new IOException(
33776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            "Expected JSON document to start with '[' or '{' but was " + token);
33876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                }
33976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return firstToken;
34076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case EMPTY_ARRAY:
34176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return nextInArray(true);
34276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case NONEMPTY_ARRAY:
34376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return nextInArray(false);
34476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case EMPTY_OBJECT:
34576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return nextInObject(true);
34676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case DANGLING_NAME:
34776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return objectValue();
34876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case NONEMPTY_OBJECT:
34976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return nextInObject(false);
35076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case NONEMPTY_DOCUMENT:
351eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                try {
352eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                    JsonToken token = nextValue();
353eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                    if (lenient) {
354eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                        return token;
355eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                    }
356eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                    throw syntaxError("Expected EOF");
357eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                } catch (EOFException e) {
358eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                    return token = JsonToken.END_DOCUMENT; // TODO: avoid throwing here?
359eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson                }
36076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case CLOSED:
36176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                throw new IllegalStateException("JsonReader is closed");
36276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            default:
36376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                throw new AssertionError();
36476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
36576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
36676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
36776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
36876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Advances the cursor in the JSON stream to the next token.
36976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
37076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken advance() throws IOException {
3719d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
37276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
37376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        JsonToken result = token;
37476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        token = null;
37576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        value = null;
37676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        name = null;
37776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
37876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
37976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
38076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
38176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the next token, a {@link JsonToken#NAME property name}, and
38276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * consumes it.
38376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
38476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IOException if the next token in the stream is not a property
38576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     name.
38676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
38776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public String nextName() throws IOException {
3889d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
3891ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        if (token != JsonToken.NAME) {
39076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            throw new IllegalStateException("Expected a name but was " + peek());
39176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
39276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        String result = name;
39376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
39476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
39576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
39676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
39776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
39876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the {@link JsonToken#STRING string} value of the next token,
39976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * consuming it. If the next token is a number, this method will return its
40076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * string form.
40176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
40276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IllegalStateException if the next token is not a string or if
40376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     this reader is closed.
40476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
40576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public String nextString() throws IOException {
4061ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        peek();
4079d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
40876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            throw new IllegalStateException("Expected a string but was " + peek());
40976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
41076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
41176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        String result = value;
41276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
41376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
41476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
41576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
41676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
41776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the {@link JsonToken#BOOLEAN boolean} value of the next token,
41876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * consuming it.
41976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
42076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IllegalStateException if the next token is not a boolean or if
42176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     this reader is closed.
42276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
42376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public boolean nextBoolean() throws IOException {
4249d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
4259d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != JsonToken.BOOLEAN) {
4269d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            throw new IllegalStateException("Expected a boolean but was " + token);
42776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
42876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
4299d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        boolean result = (value == TRUE);
43076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
43176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
43276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
43376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
43476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
43576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Consumes the next token from the JSON stream and asserts that it is a
43676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * literal null.
43776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
43876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IllegalStateException if the next token is not null or if this
43976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     reader is closed.
44076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
44176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void nextNull() throws IOException {
4429d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
4439d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != JsonToken.NULL) {
4449d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            throw new IllegalStateException("Expected null but was " + token);
44576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
44676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
44776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
44876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
44976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
45076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
45176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the {@link JsonToken#NUMBER double} value of the next token,
45276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * consuming it. If the next token is a string, this method will attempt to
4539d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * parse it as a double using {@link Double#parseDouble(String)}.
45476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
45576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IllegalStateException if the next token is not a literal value.
45676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
45776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public double nextDouble() throws IOException {
4589d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
4599d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
4609d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            throw new IllegalStateException("Expected a double but was " + token);
46176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
46276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
46376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        double result = Double.parseDouble(value);
46476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
46576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
46676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
46776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
46876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
46976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the {@link JsonToken#NUMBER long} value of the next token,
47076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * consuming it. If the next token is a string, this method will attempt to
47176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * parse it as a long. If the next token's numeric value cannot be exactly
47276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * represented by a Java {@code long}, this method throws.
47376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
47476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IllegalStateException if the next token is not a literal value.
47576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws NumberFormatException if the next literal value cannot be parsed
47676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     as a number, or exactly represented as a long.
47776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
47876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public long nextLong() throws IOException {
4799d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
4809d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
4819d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            throw new IllegalStateException("Expected a long but was " + token);
48276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
48376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
48476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        long result;
48576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        try {
48676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            result = Long.parseLong(value);
48776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } catch (NumberFormatException ignored) {
48876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
48976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            result = (long) asDouble;
49076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            if ((double) result != asDouble) {
49176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                throw new NumberFormatException(value);
49276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
49376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
49476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
49576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
49676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
49776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
49876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
49976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
50076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the {@link JsonToken#NUMBER int} value of the next token,
50176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * consuming it. If the next token is a string, this method will attempt to
50276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * parse it as an int. If the next token's numeric value cannot be exactly
50376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * represented by a Java {@code int}, this method throws.
50476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
50576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws IllegalStateException if the next token is not a literal value.
50676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws NumberFormatException if the next literal value cannot be parsed
50776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     as a number, or exactly represented as an int.
50876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
50976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public int nextInt() throws IOException {
5109d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        peek();
5119d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
5129d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            throw new IllegalStateException("Expected an int but was " + token);
51376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
51476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
51576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        int result;
51676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        try {
51776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            result = Integer.parseInt(value);
51876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } catch (NumberFormatException ignored) {
51976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
52076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            result = (int) asDouble;
52176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            if ((double) result != asDouble) {
52276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                throw new NumberFormatException(value);
52376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
52476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
52576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
52676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        advance();
52776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return result;
52876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
52976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
53076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
53176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Closes this JSON reader and the underlying {@link Reader}.
53276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
53376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void close() throws IOException {
53476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        value = null;
53576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        token = null;
53676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        stack.clear();
53776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        stack.add(JsonScope.CLOSED);
53876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        in.close();
53976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
54076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
54176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
54276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Skips the next value recursively. If it is an object or array, all nested
54376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * elements are skipped. This method is intended for use when the JSON token
54476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * stream contains unrecognized or unhandled values.
54576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
54676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    public void skipValue() throws IOException {
547d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson        skipping = true;
548d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson        try {
549d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson            int count = 0;
550d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson            do {
551d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                JsonToken token = advance();
552d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                if (token == JsonToken.BEGIN_ARRAY || token == JsonToken.BEGIN_OBJECT) {
553d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                    count++;
554d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                } else if (token == JsonToken.END_ARRAY || token == JsonToken.END_OBJECT) {
555d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                    count--;
556d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                }
557d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson            } while (count != 0);
558d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson        } finally {
559d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson            skipping = false;
560d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson        }
56176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
56276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
56376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonScope peekStack() {
56476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return stack.get(stack.size() - 1);
56576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
56676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
56776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonScope pop() {
56876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return stack.remove(stack.size() - 1);
56976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
57076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
57176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private void push(JsonScope newTop) {
57276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        stack.add(newTop);
57376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
57476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
57576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
57676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Replace the value on the top of the stack with the given value.
57776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
57876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private void replaceTop(JsonScope newTop) {
57976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        stack.set(stack.size() - 1, newTop);
58076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
58176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
58276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken nextInArray(boolean firstElement) throws IOException {
58376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        if (firstElement) {
5841ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            replaceTop(JsonScope.NONEMPTY_ARRAY);
58576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } else {
5861ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            /* Look for a comma before each element after the first element. */
58776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            switch (nextNonWhitespace()) {
58876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case ']':
58976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    pop();
59076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    return token = JsonToken.END_ARRAY;
59176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case ';':
5921ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                    checkLenient(); // fall-through
5931ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                case ',':
59476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    break;
59576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                default:
59676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    throw syntaxError("Unterminated array");
59776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
59876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
59976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
6001ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        switch (nextNonWhitespace()) {
6011ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            case ']':
6021ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                if (firstElement) {
6031ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                    pop();
6041ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                    return token = JsonToken.END_ARRAY;
6051ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                }
6061ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                // fall-through to handle ",]"
6071ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            case ';':
6081ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            case ',':
6091ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                /* In lenient mode, a 0-length literal means 'null' */
6101ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                checkLenient();
6111ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                pos--;
6121ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                value = "null";
6131ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                return token = JsonToken.NULL;
6141ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            default:
6151ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                pos--;
6161ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                return nextValue();
6171ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        }
61876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
61976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
62076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken nextInObject(boolean firstElement) throws IOException {
62176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        /*
62276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson         * Read delimiters. Either a comma/semicolon separating this and the
62376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson         * previous name-value pair, or a close brace to denote the end of the
62476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson         * object.
62576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson         */
62676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        if (firstElement) {
62776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            /* Peek to see if this is the empty object. */
62876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            switch (nextNonWhitespace()) {
62976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '}':
63076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    pop();
63176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    return token = JsonToken.END_OBJECT;
63276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                default:
63376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    pos--;
63476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
63576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } else {
63676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            switch (nextNonWhitespace()) {
63776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '}':
63876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    pop();
63976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    return token = JsonToken.END_OBJECT;
64076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case ';':
64176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case ',':
64276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    break;
64376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                default:
64476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    throw syntaxError("Unterminated object");
64576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
64676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
64776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
64876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        /* Read the name. */
64976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        int quote = nextNonWhitespace();
65076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        switch (quote) {
65176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '\'':
6521ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                checkLenient(); // fall-through
65376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '"':
65476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                name = nextString((char) quote);
65576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                break;
65676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            default:
6571ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                checkLenient();
65876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                pos--;
6599d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                name = nextLiteral(false);
66076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                if (name.isEmpty()) {
66176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    throw syntaxError("Expected name");
66276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                }
66376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
66476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
66576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        replaceTop(JsonScope.DANGLING_NAME);
66676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return token = JsonToken.NAME;
66776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
66876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
66976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken objectValue() throws IOException {
67076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        /*
6711ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson         * Read the name/value separator. Usually a colon ':'. In lenient mode
6721ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson         * we also accept an equals sign '=', or an arrow "=>".
67376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson         */
6741ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        switch (nextNonWhitespace()) {
6751ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            case ':':
6761ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                break;
6771ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            case '=':
6781ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                checkLenient();
6791ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
6801ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                    pos++;
6811ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                }
6821ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                break;
6831ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            default:
6841ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                throw syntaxError("Expected ':'");
68576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
68676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
68776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        replaceTop(JsonScope.NONEMPTY_OBJECT);
68876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return nextValue();
68976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
69076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
69176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken nextValue() throws IOException {
69276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        int c = nextNonWhitespace();
69376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        switch (c) {
69476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '{':
69576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                push(JsonScope.EMPTY_OBJECT);
69676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return token = JsonToken.BEGIN_OBJECT;
69776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
69876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '[':
69976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                push(JsonScope.EMPTY_ARRAY);
70076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return token = JsonToken.BEGIN_ARRAY;
70176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
70276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '\'':
7031ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                checkLenient(); // fall-through
70476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '"':
70576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                value = nextString((char) c);
70676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return token = JsonToken.STRING;
70776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
70876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            default:
70976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                pos--;
71076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return readLiteral();
71176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
71276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
71376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
71476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
71576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns true once {@code limit - pos >= minimum}. If the data is
71676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * exhausted before that many characters are available, this returns
71776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * false.
71876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
71976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private boolean fillBuffer(int minimum) throws IOException {
720febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        // Before clobbering the old characters, update where buffer starts
721febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        for (int i = 0; i < pos; i++) {
722febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            if (buffer[i] == '\n') {
723febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                bufferStartLine++;
724febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                bufferStartColumn = 1;
725febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            } else {
726febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                bufferStartColumn++;
727febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            }
728febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        }
729febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson
73076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        if (limit != pos) {
73176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            limit -= pos;
73276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            System.arraycopy(buffer, pos, buffer, 0, limit);
73376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } else {
73476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            limit = 0;
73576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
73676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
73776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        pos = 0;
73876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        int total;
73976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) {
74076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            limit += total;
7417a2c813d304b910b00046115efb0f462e6431a64Jesse Wilson
7427a2c813d304b910b00046115efb0f462e6431a64Jesse Wilson            // if this is the first read, consume an optional byte order mark (BOM) if it exists
743d1ad3c2c3a675c4018f0f43577b203858dad767aJesse Wilson                if (bufferStartLine == 1 && bufferStartColumn == 1
744d1ad3c2c3a675c4018f0f43577b203858dad767aJesse Wilson                        && limit > 0 && buffer[0] == '\ufeff') {
7457a2c813d304b910b00046115efb0f462e6431a64Jesse Wilson                pos++;
7467a2c813d304b910b00046115efb0f462e6431a64Jesse Wilson                bufferStartColumn--;
7477a2c813d304b910b00046115efb0f462e6431a64Jesse Wilson            }
7487a2c813d304b910b00046115efb0f462e6431a64Jesse Wilson
74976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            if (limit >= minimum) {
75076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return true;
75176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
75276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
75376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return false;
75476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
75576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
756febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    private int getLineNumber() {
757febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        int result = bufferStartLine;
758febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        for (int i = 0; i < pos; i++) {
759febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            if (buffer[i] == '\n') {
760febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                result++;
761febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            }
762febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        }
763febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        return result;
764febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    }
765febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson
766febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    private int getColumnNumber() {
767febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        int result = bufferStartColumn;
768febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        for (int i = 0; i < pos; i++) {
769febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            if (buffer[i] == '\n') {
770febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                result = 1;
771febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            } else {
772febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                result++;
773febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson            }
774febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        }
775febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        return result;
776febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson    }
777febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson
77876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private int nextNonWhitespace() throws IOException {
77976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        while (pos < limit || fillBuffer(1)) {
78076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            int c = buffer[pos++];
78176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            switch (c) {
78276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '\t':
78376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case ' ':
78476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '\n':
78576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '\r':
78676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    continue;
78776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
78876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '/':
78976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    if (pos == limit && !fillBuffer(1)) {
79076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        return c;
79176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    }
79276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
7931ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                    checkLenient();
79476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    char peek = buffer[pos];
79576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    switch (peek) {
79676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        case '*':
79776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            // skip a /* c-style comment */
79876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            pos++;
79976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            if (!skipTo("*/")) {
80076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                                throw syntaxError("Unterminated comment");
80176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            }
80276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            pos += 2;
80376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            continue;
80476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
80576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        case '/':
80676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            // skip a // end-of-line comment
80776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            pos++;
80876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            skipToEndOfLine();
80976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            continue;
81076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
81176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        default:
81276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                            return c;
81376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    }
81476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
81576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                case '#':
81676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    /*
81776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                     * Skip a # hash end-of-line comment. The JSON RFC doesn't
81876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                     * specify this behaviour, but it's required to parse
81976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                     * existing documents. See http://b/2571423.
82076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                     */
8211ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson                    checkLenient();
82276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    skipToEndOfLine();
82376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    continue;
82476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
82576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                default:
82676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    return c;
82776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
82876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
82976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
830eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson        throw new EOFException("End of input");
83176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
83276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
8331ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    private void checkLenient() throws IOException {
8341ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        if (!lenient) {
8351ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson            throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON");
8361ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson        }
8371ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson    }
8381ba417140554dbd57602a1f4b453fc42363cf394Jesse Wilson
83976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
84076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Advances the position until after the next newline character. If the line
84176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
84276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * caller.
84376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
84476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private void skipToEndOfLine() throws IOException {
84576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        while (pos < limit || fillBuffer(1)) {
84676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            char c = buffer[pos++];
84776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            if (c == '\r' || c == '\n') {
84876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                break;
84976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
85076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
85176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
85276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
85376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private boolean skipTo(String toFind) throws IOException {
85476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        outer:
855d1ad3c2c3a675c4018f0f43577b203858dad767aJesse Wilson        for (; pos + toFind.length() <= limit || fillBuffer(toFind.length()); pos++) {
85676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            for (int c = 0; c < toFind.length(); c++) {
85776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                if (buffer[pos + c] != toFind.charAt(c)) {
85876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    continue outer;
85976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                }
86076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
86176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            return true;
86276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
86376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return false;
86476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
86576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
86676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
86776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Returns the string up to but not including {@code quote}, unescaping any
86876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * character escape sequences encountered along the way. The opening quote
86976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * should have already been read. This consumes the closing quote, but does
87076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * not include it in the returned string.
87176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
87276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @param quote either ' or ".
87376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws NumberFormatException if any unicode escape sequences are
87476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     malformed.
87576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
87676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private String nextString(char quote) throws IOException {
87776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        StringBuilder builder = null;
87876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        do {
87976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            /* the index of the first character not yet appended to the builder. */
88076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            int start = pos;
88176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            while (pos < limit) {
88276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                int c = buffer[pos++];
88376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
88476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                if (c == quote) {
885d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                    if (skipping) {
886d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                        return "skipped!";
887d07fb882f84e9fa7b758870261747456f2752ba5Jesse Wilson                    } else if (builder == null) {
888847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilson                        return stringPool.get(buffer, start, pos - start - 1);
88976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    } else {
89076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        builder.append(buffer, start, pos - start - 1);
89176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        return builder.toString();
89276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    }
89376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
89476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                } else if (c == '\\') {
89576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    if (builder == null) {
89676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                        builder = new StringBuilder();
89776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    }
89876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    builder.append(buffer, start, pos - start - 1);
89976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    builder.append(readEscapeCharacter());
90076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    start = pos;
90176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                }
90276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
90376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
90476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            if (builder == null) {
90576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                builder = new StringBuilder();
90676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
90776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            builder.append(buffer, start, pos - start);
90876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } while (fillBuffer(1));
90976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
91076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        throw syntaxError("Unterminated string");
91176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
91276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
91376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
9149d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * Reads the value up to but not including any delimiter characters. This
91576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * does not consume the delimiter character.
9169d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     *
9179d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * @param assignOffsetsOnly true for this method to only set the valuePos
9189d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     *     and valueLength fields and return a null result. This only works if
9199d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     *     the literal is short; a string is returned otherwise.
92076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
9219d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private String nextLiteral(boolean assignOffsetsOnly) throws IOException {
92276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        StringBuilder builder = null;
9239d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        valuePos = -1;
9249d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        valueLength = 0;
9259d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        int i = 0;
9269d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
9279d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        findNonLiteralCharacter:
9289d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        while (true) {
9299d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            for (; pos + i < limit; i++) {
9309d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                switch (buffer[pos + i]) {
9319d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '/':
9329d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '\\':
9339d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case ';':
9349d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '#':
9359d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '=':
9369d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                    checkLenient(); // fall-through
9379d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '{':
9389d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '}':
9399d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '[':
9409d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case ']':
9419d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case ':':
9429d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case ',':
9439d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case ' ':
9449d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '\t':
9459d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '\f':
9469d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '\r':
9479d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                case '\n':
9489d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                    break findNonLiteralCharacter;
9499d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                }
9509d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            }
9519d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
9529d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            /*
9539d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson             * Attempt to load the entire literal into the buffer at once. If
9549d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson             * we run out of input, add a non-literal character at the end so
9559d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson             * that decoding doesn't need to do bounds checks.
9569d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson             */
9579d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            if (i < buffer.length) {
9589d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                if (fillBuffer(i + 1)) {
9599d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                    continue;
9609d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                } else {
9619d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                    buffer[limit] = '\0';
9629d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                    break;
96376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                }
96476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
96576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
9669d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            // use a StringBuilder when the value is too long. It must be an unquoted string.
96776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            if (builder == null) {
96876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                builder = new StringBuilder();
96976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
9709d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            builder.append(buffer, pos, i);
9719d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            valueLength += i;
9729d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            pos += i;
9739d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            i = 0;
9749d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            if (!fillBuffer(1)) {
9759d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                break;
9769d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            }
9779d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
97876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
9799d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        String result;
9809d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (assignOffsetsOnly && builder == null) {
9819d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            valuePos = pos;
9829d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            result = null;
9839d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else if (skipping) {
9849d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            result = "skipped!";
9859d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else if (builder == null) {
986847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilson            result = stringPool.get(buffer, pos, i);
9879d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else {
9889d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            builder.append(buffer, pos, i);
9899d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            result = builder.toString();
9909d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
9919d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        valueLength += i;
9929d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        pos += i;
9939d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        return result;
99476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
99576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
99676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    @Override public String toString() {
99776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return getClass().getSimpleName() + " near " + getSnippet();
99876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
99976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
100076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
100176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Unescapes the character identified by the character or characters that
100276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * immediately follow a backslash. The backslash '\' should have already
100376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * been read. This supports both unicode escapes "u000A" and two-character
100476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * escapes "\n".
100576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *
100676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * @throws NumberFormatException if any unicode escape sequences are
100776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     *     malformed.
100876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
100976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private char readEscapeCharacter() throws IOException {
101076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        if (pos == limit && !fillBuffer(1)) {
101176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            throw syntaxError("Unterminated escape sequence");
101276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
101376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
101476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        char escaped = buffer[pos++];
101576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        switch (escaped) {
101676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case 'u':
101776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                if (pos + 4 > limit && !fillBuffer(4)) {
101876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                    throw syntaxError("Unterminated escape sequence");
101976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                }
1020847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilson                String hex = stringPool.get(buffer, pos, 4);
102176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                pos += 4;
102276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return (char) Integer.parseInt(hex, 16);
102376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
102476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case 't':
102576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return '\t';
102676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
102776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case 'b':
102876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return '\b';
102976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
103076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case 'n':
103176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return '\n';
103276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
103376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case 'r':
103476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return '\r';
103576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
103676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case 'f':
103776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return '\f';
103876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
103976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '\'':
104076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '"':
104176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            case '\\':
104276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            default:
104376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson                return escaped;
104476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
104576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
104676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
104776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
104876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Reads a null, boolean, numeric or unquoted string literal value.
104976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
105076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private JsonToken readLiteral() throws IOException {
10519d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        value = nextLiteral(true);
10529d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (valueLength == 0) {
105376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            throw syntaxError("Expected literal value");
105476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
10559d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        token = decodeLiteral();
10569d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (token == JsonToken.STRING) {
10579d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson          checkLenient();
10589d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
10599d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        return token;
106076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
106176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
106276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
106376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Assigns {@code nextToken} based on the value of {@code nextValue}.
106476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
10659d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private JsonToken decodeLiteral() throws IOException {
10669d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (valuePos == -1) {
10679d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            // it was too long to fit in the buffer so it can only be a string
10689d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.STRING;
10699d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else if (valueLength == 4
10709d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('n' == buffer[valuePos    ] || 'N' == buffer[valuePos    ])
10719d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('u' == buffer[valuePos + 1] || 'U' == buffer[valuePos + 1])
10729d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])
10739d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('l' == buffer[valuePos + 3] || 'L' == buffer[valuePos + 3])) {
10749d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            value = "null";
10759d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.NULL;
10769d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else if (valueLength == 4
10779d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('t' == buffer[valuePos    ] || 'T' == buffer[valuePos    ])
10789d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('r' == buffer[valuePos + 1] || 'R' == buffer[valuePos + 1])
10799d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('u' == buffer[valuePos + 2] || 'U' == buffer[valuePos + 2])
10809d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('e' == buffer[valuePos + 3] || 'E' == buffer[valuePos + 3])) {
10819d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            value = TRUE;
10829d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.BOOLEAN;
10839d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else if (valueLength == 5
10849d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('f' == buffer[valuePos    ] || 'F' == buffer[valuePos    ])
10859d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('a' == buffer[valuePos + 1] || 'A' == buffer[valuePos + 1])
10869d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])
10879d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('s' == buffer[valuePos + 3] || 'S' == buffer[valuePos + 3])
10889d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                && ('e' == buffer[valuePos + 4] || 'E' == buffer[valuePos + 4])) {
10899d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            value = FALSE;
10909d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.BOOLEAN;
109176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        } else {
1092847cf342c956eac3dec03b7b29fcb188ffe8804fJesse Wilson            value = stringPool.get(buffer, valuePos, valueLength);
10939d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return decodeNumber(buffer, valuePos, valueLength);
10949d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
10959d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    }
10969d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
10979d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    /**
10989d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * Determine whether the characters is a JSON number. Numbers are of the
10999d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * form -12.34e+56. Fractional and exponential parts are optional. Leading
11009d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * zeroes are not allowed in the value or exponential part, but are allowed
11019d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     * in the fraction.
11029d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson     */
11039d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson    private JsonToken decodeNumber(char[] chars, int offset, int length) {
11049d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        int i = offset;
11059d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        int c = chars[i];
11069d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
11079d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (c == '-') {
11089d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            c = chars[++i];
11099d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
11109d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
11119d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (c == '0') {
11129d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            c = chars[++i];
11139d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else if (c >= '1' && c <= '9') {
11149d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            c = chars[++i];
11159d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            while (c >= '0' && c <= '9') {
11169d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                c = chars[++i];
11179d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            }
11189d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else {
11199d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.STRING;
11209d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
11219d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
11229d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (c == '.') {
11239d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            c = chars[++i];
11249d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            while (c >= '0' && c <= '9') {
11259d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                c = chars[++i];
11269d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            }
11279d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
11289d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
11299d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (c == 'e' || c == 'E') {
11309d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            c = chars[++i];
11319d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            if (c == '+' || c == '-') {
11329d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                c = chars[++i];
113376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson            }
11349d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            if (c >= '0' && c <= '9') {
11359d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                c = chars[++i];
11369d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                while (c >= '0' && c <= '9') {
11379d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                    c = chars[++i];
11389d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                }
11399d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            } else {
11409d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson                return JsonToken.STRING;
11419d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            }
11429d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        }
11439d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson
11449d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        if (i == offset + length) {
11459d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.NUMBER;
11469d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson        } else {
11479d9b4e70a1e7f9ffb6cedd8a86fdd926f2a28202Jesse Wilson            return JsonToken.STRING;
114876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        }
114976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
115076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
115176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    /**
115276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * Throws a new IO exception with the given message and a context snippet
115376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     * with this reader's content.
115476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson     */
1155eb97c0ddc063176c26065fc6855188edf0c16e03Jesse Wilson    private IOException syntaxError(String message) throws IOException {
1156febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson        throw new MalformedJsonException(message
1157febae4ed18953098fec2126c7f883213e14469c9Jesse Wilson                + " at line " + getLineNumber() + " column " + getColumnNumber());
115876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
115976d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson
116076d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    private CharSequence getSnippet() {
116176d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        StringBuilder snippet = new StringBuilder();
116276d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        int beforePos = Math.min(pos, 20);
116376d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        snippet.append(buffer, pos - beforePos, beforePos);
116476d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        int afterPos = Math.min(limit - pos, 20);
116576d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        snippet.append(buffer, pos, afterPos);
116676d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson        return snippet;
116776d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson    }
116876d7e20a75d24afb2f5011a7646dbde8aaa52087Jesse Wilson}
1169