From 0697573a4c48d9ecc717d6e77a4dd6806621487a Mon Sep 17 00:00:00 2001 From: deirn Date: Wed, 7 Aug 2024 18:00:19 +0700 Subject: [PATCH 01/16] add streaming json5 api to mcless --- .../mcless/json5/stream/Json5Reader.java | 1606 +++++++++++++++++ .../waila/mcless/json5/stream/Json5Scope.java | 82 + .../mcless/json5/stream/Json5Writer.java | 741 ++++++++ 3 files changed, 2429 insertions(+) create mode 100644 src/minecraftless/java/mcp/mobius/waila/mcless/json5/stream/Json5Reader.java create mode 100644 src/minecraftless/java/mcp/mobius/waila/mcless/json5/stream/Json5Scope.java create mode 100644 src/minecraftless/java/mcp/mobius/waila/mcless/json5/stream/Json5Writer.java diff --git a/src/minecraftless/java/mcp/mobius/waila/mcless/json5/stream/Json5Reader.java b/src/minecraftless/java/mcp/mobius/waila/mcless/json5/stream/Json5Reader.java new file mode 100644 index 00000000..1d42c6f9 --- /dev/null +++ b/src/minecraftless/java/mcp/mobius/waila/mcless/json5/stream/Json5Reader.java @@ -0,0 +1,1606 @@ +// This file was a part of Quilt Parsers, modified to remove unused members. +// https://github.com/QuiltMC/quilt-parsers/blob/00803c4e70fb0cf93765593eaae5c781b1505bee/json/src/main/java/org/quiltmc/parsers/json/JsonReader.java +// @formatter:off + +/* + * Copyright 2010 Google Inc. + * Copyright 2021-2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mcp.mobius.waila.mcless.json5.stream; + +import java.io.*; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Objects; + +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.MalformedJsonException; + +/* + * The following changes have been applied from the original in GSON: + * - The lenient mode has been removed. + * - Now supports parsing JSONC and JSON5 + * + * You may view the original, including its license header, here: + * https://github.com/google/gson/blob/530cb7447089ccc12dc2009c17f468ddf2cd61ca/gson/src/main/java/com/google/gson/stream/JsonReader.java + */ + +/** + * Reads a {@linkplain JsonFormat JSON-family} + * encoded value as a stream of tokens. This stream includes both literal + * values (strings, numbers, booleans, and nulls) as well as the begin and + * end delimiters of objects and arrays. The tokens are traversed in + * depth-first order, the same order that they appear in the JSON document. + * Within JSON objects, name/value pairs are represented by a single token. + * + *

Parsing JSON

+ * To create a recursive descent parser for your own JSON streams, first create + * an entry point method that creates a {@code JsonReader}. + * + *

Next, create handler methods for each structure in your JSON text. You'll + * need a method for each object type and for each array type. + *

+ *

When a nested object or array is encountered, delegate to the + * corresponding handler method. + * + *

When an unknown name is encountered, strict parsers should fail with an + * exception. Lenient parsers should call {@link #skipValue()} to recursively + * skip the value's nested tokens, which may otherwise conflict. + * + *

If a value may be null, you should first check using {@link #peek()}. + * Null literals can be consumed using either {@link #nextNull()} or {@link + * #skipValue()}. + * + *

Example

+ * Suppose we'd like to parse a stream of messages such as the following:
 {@code
+ * [
+ *   {
+ *     id: 912345678901,
+ *     text: "How do I read a JSON stream in Java?",
+ *     geo: null,
+ *     user: {
+ *       "name": "json_newb",
+ *       followers_count: 41,
+ *      }
+ *   },
+ *   {
+ *   /*
+ *    * Look mom, block comments!
+ *    *\/
+ *     "id": 912345678902,
+ *     "text": "@json_newb just use JsonReader!",
+ *     "geo": [-Infinity, NaN], // wow, broken floating point types!
+ *     "user": {
+ *       "name": "jesse",
+ *       "followers_count": 2
+ *     }
+ *   }
+ * ]}
+ * This code implements the parser for the above structure:
   {@code
+ *
+ *   public List readJsonStream(InputStream in) throws IOException {
+ *     JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
+ *     try {
+ *       return readMessagesArray(reader);
+ *     } finally {
+ *       reader.close();
+ *     }
+ *   }
+ *
+ *   public List readMessagesArray(JsonReader reader) throws IOException {
+ *     List messages = new ArrayList();
+ *
+ *     reader.beginArray();
+ *     while (reader.hasNext()) {
+ *       messages.add(readMessage(reader));
+ *     }
+ *     reader.endArray();
+ *     return messages;
+ *   }
+ *
+ *   public Message readMessage(JsonReader reader) throws IOException {
+ *     long id = -1;
+ *     String text = null;
+ *     User user = null;
+ *     List geo = null;
+ *
+ *     reader.beginObject();
+ *     while (reader.hasNext()) {
+ *       String name = reader.nextName();
+ *       if (name.equals("id")) {
+ *         id = reader.nextLong();
+ *       } else if (name.equals("text")) {
+ *         text = reader.nextString();
+ *       } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
+ *         geo = readDoublesArray(reader);
+ *       } else if (name.equals("user")) {
+ *         user = readUser(reader);
+ *       } else {
+ *         reader.skipValue();
+ *       }
+ *     }
+ *     reader.endObject();
+ *     return new Message(id, text, user, geo);
+ *   }
+ *
+ *   public List readDoublesArray(JsonReader reader) throws IOException {
+ *     List doubles = new ArrayList();
+ *
+ *     reader.beginArray();
+ *     while (reader.hasNext()) {
+ *       doubles.add(reader.nextDouble());
+ *     }
+ *     reader.endArray();
+ *     return doubles;
+ *   }
+ *
+ *   public User readUser(JsonReader reader) throws IOException {
+ *     String username = null;
+ *     int followersCount = -1;
+ *
+ *     reader.beginObject();
+ *     while (reader.hasNext()) {
+ *       String name = reader.nextName();
+ *       if (name.equals("name")) {
+ *         username = reader.nextString();
+ *       } else if (name.equals("followers_count")) {
+ *         followersCount = reader.nextInt();
+ *       } else {
+ *         reader.skipValue();
+ *       }
+ *     }
+ *     reader.endObject();
+ *     return new User(username, followersCount);
+ *   }}
+ * + *

Number Handling

+ * This reader permits numeric values to be read as strings and string values to + * be read as numbers. For example, both elements of the JSON array {@code + * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}. + * This behavior is intended to prevent lossy numeric conversions: double is + * JavaScript's only numeric type and very large values like {@code + * 9007199254740993} cannot be represented exactly on that platform. To minimize + * precision loss, extremely large values should be written and read as strings + * in JSON. + * + *

Non-Execute Prefix

+ * Web servers that serve private data using JSON may be vulnerable to
Cross-site + * request forgery attacks. In such an attack, a malicious site gains access + * to a private JSON file by executing it with an HTML {@code