From df5f79584312cf4f6cc7ec1d73a78f6ba475c9ad Mon Sep 17 00:00:00 2001 From: ousttrue Date: Fri, 28 Dec 2018 20:36:46 +0900 Subject: [PATCH] Squashed 'UniJSON/' content from commit 8e22468 git-subtree-dir: UniJSON git-subtree-split: 8e224689031f2a5e6ea30872e60fe808ddfdc31d --- .circleci/config.yml | 63 ++ Editor.meta | 9 + Editor/Tests.meta | 9 + Editor/Tests/IWriteStreamTest.cs | 44 + Editor/Tests/IWriteStreamTest.cs.meta | 12 + Editor/Tests/Json.meta | 9 + Editor/Tests/Json/JsonDiffTests.cs | 71 ++ Editor/Tests/Json/JsonDiffTests.cs.meta | 12 + Editor/Tests/Json/JsonFormatterTest.cs | 47 ++ Editor/Tests/Json/JsonFormatterTest.cs.meta | 12 + Editor/Tests/Json/JsonParserTest.cs | 354 ++++++++ Editor/Tests/Json/JsonParserTest.cs.meta | 12 + Editor/Tests/Json/JsonSerializerTests.cs | 152 ++++ Editor/Tests/Json/JsonSerializerTests.cs.meta | 12 + Editor/Tests/Json/JsonValueTests.cs | 41 + Editor/Tests/Json/JsonValueTests.cs.meta | 3 + Editor/Tests/Json/SchemaTests.cs | 134 ++++ Editor/Tests/Json/SchemaTests.cs.meta | 12 + Editor/Tests/Json/ValidatorTests.cs | 251 ++++++ Editor/Tests/Json/ValidatorTests.cs.meta | 12 + Editor/Tests/MsgPack.meta | 9 + Editor/Tests/MsgPack/ArrayTest.cs | 92 +++ Editor/Tests/MsgPack/ArrayTest.cs.meta | 12 + Editor/Tests/MsgPack/BooleanTest.cs | 50 ++ Editor/Tests/MsgPack/BooleanTest.cs.meta | 12 + Editor/Tests/MsgPack/FloatTest.cs | 50 ++ Editor/Tests/MsgPack/FloatTest.cs.meta | 12 + Editor/Tests/MsgPack/IntTest.cs | 220 +++++ Editor/Tests/MsgPack/IntTest.cs.meta | 12 + Editor/Tests/MsgPack/MapTest.cs | 120 +++ Editor/Tests/MsgPack/MapTest.cs.meta | 12 + Editor/Tests/MsgPack/RawTest.cs | 34 + Editor/Tests/MsgPack/RawTest.cs.meta | 12 + Editor/Tests/MsgPack/StringTest.cs | 36 + Editor/Tests/MsgPack/StringTest.cs.meta | 12 + Editor/Tests/MsgPack/TimeTests.cs | 50 ++ Editor/Tests/MsgPack/TimeTests.cs.meta | 12 + Editor/Tests/RPCTests.cs | 98 +++ Editor/Tests/RPCTests.cs.meta | 12 + Editor/Tests/Toml.meta | 9 + Editor/Tests/Toml/TomlParserTests.cs | 128 +++ Editor/Tests/Toml/TomlParserTests.cs.meta | 12 + Editor/Tests/TreeTest.cs | 129 +++ Editor/Tests/TreeTest.cs.meta | 12 + Editor/Tests/Utf8StringTest.cs | 168 ++++ Editor/Tests/Utf8StringTest.cs.meta | 11 + LICENSE | 21 + LICENSE.meta | 8 + Profiling.meta | 9 + Profiling/.gitignore | 15 + Profiling/App.config | 6 + Profiling/Program.cs | 16 + Profiling/Program.cs.meta | 12 + Profiling/Properties.meta | 9 + Profiling/Properties/AssemblyInfo.cs | 36 + Profiling/Properties/AssemblyInfo.cs.meta | 12 + Profiling/UniJSONPRofiling.csproj | 80 ++ Profiling/UniJSONPRofiling.csproj.meta | 8 + Profiling/UniJSONPRofiling.sln | 28 + Profiling/UniJSONPRofiling.sln.meta | 8 + README.md | 138 ++++ README.md.meta | 8 + Scripts.meta | 9 + Scripts/ActionDisposer.cs | 20 + Scripts/ActionDisposer.cs.meta | 12 + Scripts/ByteBuffer.cs | 90 +++ Scripts/ByteBuffer.cs.meta | 11 + Scripts/Exceptions.cs | 34 + Scripts/Exceptions.cs.meta | 12 + Scripts/Extensions.meta | 9 + Scripts/Extensions/ArraySegmentExtensions.cs | 85 ++ .../Extensions/ArraySegmentExtensions.cs.meta | 12 + Scripts/Extensions/ByteExtensions.cs | 60 ++ Scripts/Extensions/ByteExtensions.cs.meta | 12 + .../Extensions/DateTimeOffsetExtensions.cs | 21 + .../DateTimeOffsetExtensions.cs.meta | 12 + Scripts/Extensions/EnumExtensions.cs | 15 + Scripts/Extensions/EnumExtensions.cs.meta | 12 + Scripts/Extensions/ParserExtensions.cs | 52 ++ Scripts/Extensions/ParserExtensions.cs.meta | 12 + Scripts/Extensions/TypeExtensions.cs | 28 + Scripts/Extensions/TypeExtensions.cs.meta | 12 + Scripts/FormatterExtensions.cs | 71 ++ Scripts/FormatterExtensions.cs.meta | 12 + Scripts/FormatterExtensionsSerializer.cs | 186 +++++ Scripts/FormatterExtensionsSerializer.cs.meta | 12 + Scripts/GenericCast.cs | 79 ++ Scripts/GenericCast.cs.meta | 12 + Scripts/IFileSystemAccessor.cs | 53 ++ Scripts/IFileSystemAccessor.cs.meta | 12 + Scripts/IFormatter.cs | 42 + Scripts/IFormatter.cs.meta | 12 + Scripts/IStore.meta | 9 + Scripts/IStore/ByteUnion.cs | 109 +++ Scripts/IStore/ByteUnion.cs.meta | 12 + Scripts/IStore/BytesStore.cs | 288 +++++++ Scripts/IStore/BytesStore.cs.meta | 12 + Scripts/IStore/IStore.cs | 63 ++ Scripts/IStore/IStore.cs.meta | 12 + Scripts/IStore/StreamStore.cs | 149 ++++ Scripts/IStore/StreamStore.cs.meta | 12 + Scripts/IStore/StringBuilderStore.cs | 153 ++++ Scripts/IStore/StringBuilderStore.cs.meta | 12 + Scripts/ITreeNode.cs | 24 + Scripts/ITreeNode.cs.meta | 12 + Scripts/IValue.cs | 42 + Scripts/IValue.cs.meta | 12 + Scripts/Json.meta | 9 + Scripts/Json/JsonDiff.cs | 44 + Scripts/Json/JsonDiff.cs.meta | 12 + Scripts/Json/JsonFormatter.cs | 546 +++++++++++++ Scripts/Json/JsonFormatter.cs.meta | 12 + Scripts/Json/JsonParser.cs | 323 ++++++++ Scripts/Json/JsonParser.cs.meta | 12 + Scripts/Json/JsonPointer.cs | 101 +++ Scripts/Json/JsonPointer.cs.meta | 12 + Scripts/Json/JsonSchema.cs | 418 ++++++++++ Scripts/Json/JsonSchema.cs.meta | 12 + Scripts/Json/JsonSchemaAttribute.cs | 72 ++ Scripts/Json/JsonSchemaAttribute.cs.meta | 12 + Scripts/Json/JsonString.cs | 372 +++++++++ Scripts/Json/JsonString.cs.meta | 12 + Scripts/Json/JsonValue.cs | 111 +++ Scripts/Json/JsonValue.cs.meta | 12 + Scripts/JsonSchemaValidator.meta | 9 + .../IJsonSchemaValidator.cs | 86 ++ .../IJsonSchemaValidator.cs.meta | 12 + .../JsonSchemaValidator/JsonArrayValidator.cs | 261 ++++++ .../JsonArrayValidator.cs.meta | 12 + .../JsonSchemaValidator/JsonBoolValidator.cs | 51 ++ .../JsonBoolValidator.cs.meta | 12 + .../JsonDictionaryValidator.cs | 290 +++++++ .../JsonDictionaryValidator.cs.meta | 12 + .../JsonSchemaValidator/JsonEnumValidator.cs | 445 +++++++++++ .../JsonEnumValidator.cs.meta | 12 + .../JsonNumberValidator.cs | 430 ++++++++++ .../JsonNumberValidator.cs.meta | 12 + .../JsonObjectValidator.cs | 605 ++++++++++++++ .../JsonObjectValidator.cs.meta | 12 + .../JsonSchemaValidator.cs | 33 + .../JsonSchemaValidator.cs.meta | 12 + .../JsonSchemaValidatorFactory.cs | 320 ++++++++ .../JsonSchemaValidatorFactory.cs.meta | 12 + .../JsonStringValidator.cs | 147 ++++ .../JsonStringValidator.cs.meta | 12 + Scripts/ListTreeNode.meta | 9 + Scripts/ListTreeNode/ListTreeNode.cs | 417 ++++++++++ Scripts/ListTreeNode/ListTreeNode.cs.meta | 12 + .../ListTreeNodeArrayExtensions.cs | 51 ++ .../ListTreeNodeArrayExtensions.cs.meta | 12 + .../ListTreeNodeDeserializerExtensions.cs | 308 +++++++ ...ListTreeNodeDeserializerExtensions.cs.meta | 12 + .../ListTreeNode/ListTreeNodeExtensions.cs | 96 +++ .../ListTreeNodeExtensions.cs.meta | 12 + .../ListTreeNodeJsonPointerExtensions.cs | 138 ++++ .../ListTreeNodeJsonPointerExtensions.cs.meta | 12 + .../ListTreeNodeObjectExtensions.cs | 77 ++ .../ListTreeNodeObjectExtensions.cs.meta | 12 + Scripts/MsgPack.meta | 9 + Scripts/MsgPack/EndianConverter.cs | 434 ++++++++++ Scripts/MsgPack/EndianConverter.cs.meta | 12 + Scripts/MsgPack/Exceptions.cs | 13 + Scripts/MsgPack/Exceptions.cs.meta | 12 + Scripts/MsgPack/MsgPackFormatter.cs | 600 ++++++++++++++ Scripts/MsgPack/MsgPackFormatter.cs.meta | 12 + Scripts/MsgPack/MsgPackParser.cs | 421 ++++++++++ Scripts/MsgPack/MsgPackParser.cs.meta | 12 + Scripts/MsgPack/MsgPackType.cs | 313 ++++++++ Scripts/MsgPack/MsgPackType.cs.meta | 12 + Scripts/MsgPack/MsgPackTypeExtensions.cs | 341 ++++++++ Scripts/MsgPack/MsgPackTypeExtensions.cs.meta | 12 + Scripts/MsgPack/MsgPackValue.cs | 753 ++++++++++++++++++ Scripts/MsgPack/MsgPackValue.cs.meta | 12 + Scripts/Rpc.meta | 9 + Scripts/Rpc/IRpc.cs | 84 ++ Scripts/Rpc/IRpc.cs.meta | 12 + Scripts/Rpc/RpcDispatcher.cs | 80 ++ Scripts/Rpc/RpcDispatcher.cs.meta | 12 + Scripts/Toml.meta | 9 + Scripts/Toml/TomlParser.cs | 185 +++++ Scripts/Toml/TomlParser.cs.meta | 12 + Scripts/Toml/TomlValue.cs | 154 ++++ Scripts/Toml/TomlValue.cs.meta | 12 + Scripts/Utf8String.meta | 8 + Scripts/Utf8String/IUtf8String.cs | 138 ++++ Scripts/Utf8String/IUtf8String.cs.meta | 12 + Scripts/Utf8String/Utf8Iterator.cs | 199 +++++ Scripts/Utf8String/Utf8Iterator.cs.meta | 12 + Scripts/Utf8String/Utf8String.cs | 444 +++++++++++ Scripts/Utf8String/Utf8String.cs.meta | 11 + Scripts/Utf8String/Utf8StringBuilder.cs | 33 + Scripts/Utf8String/Utf8StringBuilder.cs.meta | 11 + Scripts/Utf8String/Utf8StringExtensions.cs | 341 ++++++++ .../Utf8String/Utf8StringExtensions.cs.meta | 12 + .../Utf8StringSplitterExtensions.cs | 44 + .../Utf8StringSplitterExtensions.cs.meta | 12 + 196 files changed, 15834 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 Editor.meta create mode 100644 Editor/Tests.meta create mode 100644 Editor/Tests/IWriteStreamTest.cs create mode 100644 Editor/Tests/IWriteStreamTest.cs.meta create mode 100644 Editor/Tests/Json.meta create mode 100644 Editor/Tests/Json/JsonDiffTests.cs create mode 100644 Editor/Tests/Json/JsonDiffTests.cs.meta create mode 100644 Editor/Tests/Json/JsonFormatterTest.cs create mode 100644 Editor/Tests/Json/JsonFormatterTest.cs.meta create mode 100644 Editor/Tests/Json/JsonParserTest.cs create mode 100644 Editor/Tests/Json/JsonParserTest.cs.meta create mode 100644 Editor/Tests/Json/JsonSerializerTests.cs create mode 100644 Editor/Tests/Json/JsonSerializerTests.cs.meta create mode 100644 Editor/Tests/Json/JsonValueTests.cs create mode 100644 Editor/Tests/Json/JsonValueTests.cs.meta create mode 100644 Editor/Tests/Json/SchemaTests.cs create mode 100644 Editor/Tests/Json/SchemaTests.cs.meta create mode 100644 Editor/Tests/Json/ValidatorTests.cs create mode 100644 Editor/Tests/Json/ValidatorTests.cs.meta create mode 100644 Editor/Tests/MsgPack.meta create mode 100644 Editor/Tests/MsgPack/ArrayTest.cs create mode 100644 Editor/Tests/MsgPack/ArrayTest.cs.meta create mode 100644 Editor/Tests/MsgPack/BooleanTest.cs create mode 100644 Editor/Tests/MsgPack/BooleanTest.cs.meta create mode 100644 Editor/Tests/MsgPack/FloatTest.cs create mode 100644 Editor/Tests/MsgPack/FloatTest.cs.meta create mode 100644 Editor/Tests/MsgPack/IntTest.cs create mode 100644 Editor/Tests/MsgPack/IntTest.cs.meta create mode 100644 Editor/Tests/MsgPack/MapTest.cs create mode 100644 Editor/Tests/MsgPack/MapTest.cs.meta create mode 100644 Editor/Tests/MsgPack/RawTest.cs create mode 100644 Editor/Tests/MsgPack/RawTest.cs.meta create mode 100644 Editor/Tests/MsgPack/StringTest.cs create mode 100644 Editor/Tests/MsgPack/StringTest.cs.meta create mode 100644 Editor/Tests/MsgPack/TimeTests.cs create mode 100644 Editor/Tests/MsgPack/TimeTests.cs.meta create mode 100644 Editor/Tests/RPCTests.cs create mode 100644 Editor/Tests/RPCTests.cs.meta create mode 100644 Editor/Tests/Toml.meta create mode 100644 Editor/Tests/Toml/TomlParserTests.cs create mode 100644 Editor/Tests/Toml/TomlParserTests.cs.meta create mode 100644 Editor/Tests/TreeTest.cs create mode 100644 Editor/Tests/TreeTest.cs.meta create mode 100644 Editor/Tests/Utf8StringTest.cs create mode 100644 Editor/Tests/Utf8StringTest.cs.meta create mode 100644 LICENSE create mode 100644 LICENSE.meta create mode 100644 Profiling.meta create mode 100644 Profiling/.gitignore create mode 100644 Profiling/App.config create mode 100644 Profiling/Program.cs create mode 100644 Profiling/Program.cs.meta create mode 100644 Profiling/Properties.meta create mode 100644 Profiling/Properties/AssemblyInfo.cs create mode 100644 Profiling/Properties/AssemblyInfo.cs.meta create mode 100644 Profiling/UniJSONPRofiling.csproj create mode 100644 Profiling/UniJSONPRofiling.csproj.meta create mode 100644 Profiling/UniJSONPRofiling.sln create mode 100644 Profiling/UniJSONPRofiling.sln.meta create mode 100644 README.md create mode 100644 README.md.meta create mode 100644 Scripts.meta create mode 100644 Scripts/ActionDisposer.cs create mode 100644 Scripts/ActionDisposer.cs.meta create mode 100644 Scripts/ByteBuffer.cs create mode 100644 Scripts/ByteBuffer.cs.meta create mode 100644 Scripts/Exceptions.cs create mode 100644 Scripts/Exceptions.cs.meta create mode 100644 Scripts/Extensions.meta create mode 100644 Scripts/Extensions/ArraySegmentExtensions.cs create mode 100644 Scripts/Extensions/ArraySegmentExtensions.cs.meta create mode 100644 Scripts/Extensions/ByteExtensions.cs create mode 100644 Scripts/Extensions/ByteExtensions.cs.meta create mode 100644 Scripts/Extensions/DateTimeOffsetExtensions.cs create mode 100644 Scripts/Extensions/DateTimeOffsetExtensions.cs.meta create mode 100644 Scripts/Extensions/EnumExtensions.cs create mode 100644 Scripts/Extensions/EnumExtensions.cs.meta create mode 100644 Scripts/Extensions/ParserExtensions.cs create mode 100644 Scripts/Extensions/ParserExtensions.cs.meta create mode 100644 Scripts/Extensions/TypeExtensions.cs create mode 100644 Scripts/Extensions/TypeExtensions.cs.meta create mode 100644 Scripts/FormatterExtensions.cs create mode 100644 Scripts/FormatterExtensions.cs.meta create mode 100644 Scripts/FormatterExtensionsSerializer.cs create mode 100644 Scripts/FormatterExtensionsSerializer.cs.meta create mode 100644 Scripts/GenericCast.cs create mode 100644 Scripts/GenericCast.cs.meta create mode 100644 Scripts/IFileSystemAccessor.cs create mode 100644 Scripts/IFileSystemAccessor.cs.meta create mode 100644 Scripts/IFormatter.cs create mode 100644 Scripts/IFormatter.cs.meta create mode 100644 Scripts/IStore.meta create mode 100644 Scripts/IStore/ByteUnion.cs create mode 100644 Scripts/IStore/ByteUnion.cs.meta create mode 100644 Scripts/IStore/BytesStore.cs create mode 100644 Scripts/IStore/BytesStore.cs.meta create mode 100644 Scripts/IStore/IStore.cs create mode 100644 Scripts/IStore/IStore.cs.meta create mode 100644 Scripts/IStore/StreamStore.cs create mode 100644 Scripts/IStore/StreamStore.cs.meta create mode 100644 Scripts/IStore/StringBuilderStore.cs create mode 100644 Scripts/IStore/StringBuilderStore.cs.meta create mode 100644 Scripts/ITreeNode.cs create mode 100644 Scripts/ITreeNode.cs.meta create mode 100644 Scripts/IValue.cs create mode 100644 Scripts/IValue.cs.meta create mode 100644 Scripts/Json.meta create mode 100644 Scripts/Json/JsonDiff.cs create mode 100644 Scripts/Json/JsonDiff.cs.meta create mode 100644 Scripts/Json/JsonFormatter.cs create mode 100644 Scripts/Json/JsonFormatter.cs.meta create mode 100644 Scripts/Json/JsonParser.cs create mode 100644 Scripts/Json/JsonParser.cs.meta create mode 100644 Scripts/Json/JsonPointer.cs create mode 100644 Scripts/Json/JsonPointer.cs.meta create mode 100644 Scripts/Json/JsonSchema.cs create mode 100644 Scripts/Json/JsonSchema.cs.meta create mode 100644 Scripts/Json/JsonSchemaAttribute.cs create mode 100644 Scripts/Json/JsonSchemaAttribute.cs.meta create mode 100644 Scripts/Json/JsonString.cs create mode 100644 Scripts/Json/JsonString.cs.meta create mode 100644 Scripts/Json/JsonValue.cs create mode 100644 Scripts/Json/JsonValue.cs.meta create mode 100644 Scripts/JsonSchemaValidator.meta create mode 100644 Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs create mode 100644 Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonArrayValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonArrayValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonBoolValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonBoolValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonEnumValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonEnumValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonNumberValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonNumberValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonObjectValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonObjectValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonSchemaValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonSchemaValidator.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs create mode 100644 Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs.meta create mode 100644 Scripts/JsonSchemaValidator/JsonStringValidator.cs create mode 100644 Scripts/JsonSchemaValidator/JsonStringValidator.cs.meta create mode 100644 Scripts/ListTreeNode.meta create mode 100644 Scripts/ListTreeNode/ListTreeNode.cs create mode 100644 Scripts/ListTreeNode/ListTreeNode.cs.meta create mode 100644 Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs create mode 100644 Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs.meta create mode 100644 Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs create mode 100644 Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs.meta create mode 100644 Scripts/ListTreeNode/ListTreeNodeExtensions.cs create mode 100644 Scripts/ListTreeNode/ListTreeNodeExtensions.cs.meta create mode 100644 Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs create mode 100644 Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta create mode 100644 Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs create mode 100644 Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs.meta create mode 100644 Scripts/MsgPack.meta create mode 100644 Scripts/MsgPack/EndianConverter.cs create mode 100644 Scripts/MsgPack/EndianConverter.cs.meta create mode 100644 Scripts/MsgPack/Exceptions.cs create mode 100644 Scripts/MsgPack/Exceptions.cs.meta create mode 100644 Scripts/MsgPack/MsgPackFormatter.cs create mode 100644 Scripts/MsgPack/MsgPackFormatter.cs.meta create mode 100644 Scripts/MsgPack/MsgPackParser.cs create mode 100644 Scripts/MsgPack/MsgPackParser.cs.meta create mode 100644 Scripts/MsgPack/MsgPackType.cs create mode 100644 Scripts/MsgPack/MsgPackType.cs.meta create mode 100644 Scripts/MsgPack/MsgPackTypeExtensions.cs create mode 100644 Scripts/MsgPack/MsgPackTypeExtensions.cs.meta create mode 100644 Scripts/MsgPack/MsgPackValue.cs create mode 100644 Scripts/MsgPack/MsgPackValue.cs.meta create mode 100644 Scripts/Rpc.meta create mode 100644 Scripts/Rpc/IRpc.cs create mode 100644 Scripts/Rpc/IRpc.cs.meta create mode 100644 Scripts/Rpc/RpcDispatcher.cs create mode 100644 Scripts/Rpc/RpcDispatcher.cs.meta create mode 100644 Scripts/Toml.meta create mode 100644 Scripts/Toml/TomlParser.cs create mode 100644 Scripts/Toml/TomlParser.cs.meta create mode 100644 Scripts/Toml/TomlValue.cs create mode 100644 Scripts/Toml/TomlValue.cs.meta create mode 100644 Scripts/Utf8String.meta create mode 100644 Scripts/Utf8String/IUtf8String.cs create mode 100644 Scripts/Utf8String/IUtf8String.cs.meta create mode 100644 Scripts/Utf8String/Utf8Iterator.cs create mode 100644 Scripts/Utf8String/Utf8Iterator.cs.meta create mode 100644 Scripts/Utf8String/Utf8String.cs create mode 100644 Scripts/Utf8String/Utf8String.cs.meta create mode 100644 Scripts/Utf8String/Utf8StringBuilder.cs create mode 100644 Scripts/Utf8String/Utf8StringBuilder.cs.meta create mode 100644 Scripts/Utf8String/Utf8StringExtensions.cs create mode 100644 Scripts/Utf8String/Utf8StringExtensions.cs.meta create mode 100644 Scripts/Utf8String/Utf8StringSplitterExtensions.cs create mode 100644 Scripts/Utf8String/Utf8StringSplitterExtensions.cs.meta diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..3ec37ca88 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,63 @@ +version: 2 +jobs: + update_unity_repo: + docker: + - image: circleci/buildpack-deps:latest + + working_directory: ~/repo + + environment: + UniJSON_unity_REPO: "git@github.com:ousttrue/UniJSON-unity.git" + + steps: + - add_ssh_keys: + fingerprints: + - "5b:16:4a:8a:c9:a5:2c:80:37:d4:a5:b8:1b:0d:60:27" + - run: + name: Avoid hosts unknown for github + command: echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + + - run: + name: Clone UniJSON-unity (NOT UniJSON) + command: | + git clone ${UniJSON_unity_REPO} + cd UniJSON-unity + git submodule update --init + + - run: + name: Update submodule(UniJSON) in UniJSON-unity + command: | + cd UniJSON-unity/Assets/UniJSON + git fetch && git checkout --force ${CIRCLE_SHA1} + + - run: + command: | + cd UniJSON-unity + git config user.email "yutopp+unijson-unity@users.noreply.github.com" + git config user.name "unijson-unity job" + + - run: + command: | + cd UniJSON-unity + git add Assets/UniJSON + git commit -m "[skip ci] Checkout UniJSON (${CIRCLE_SHA1})" + + - run: + command: | + cd UniJSON-unity + git status + when: on_fail + + - run: + command: | + cd UniJSON-unity + git push origin master + +workflows: + version: 2 + build_test_deploy: + jobs: + - update_unity_repo: + filters: + branches: + only: master diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 000000000..32892f94e --- /dev/null +++ b/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8feecbeea973dde4f944d365dc93e92c +folderAsset: yes +timeCreated: 1540820131 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests.meta b/Editor/Tests.meta new file mode 100644 index 000000000..64bd65103 --- /dev/null +++ b/Editor/Tests.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d7288f19b28ff044ba00cefdb6458340 +folderAsset: yes +timeCreated: 1526055787 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/IWriteStreamTest.cs b/Editor/Tests/IWriteStreamTest.cs new file mode 100644 index 000000000..e81cce645 --- /dev/null +++ b/Editor/Tests/IWriteStreamTest.cs @@ -0,0 +1,44 @@ +using NUnit.Framework; +using UniJSON; +using System.Linq; +using System.Text; +using System; + +namespace UniJSON +{ + public class StoreTests + { + [Test] + public void StringBuilderStoreTest() + { + var sb = new StringBuilder(); + var stream = new StringBuilderStore(sb); + + stream.Write("abc"); + Assert.AreEqual("abc", sb.ToString()); + + stream.Write("d"); + Assert.AreEqual("abcd", sb.ToString()); + + stream.Clear(); + stream.Write("e"); + Assert.AreEqual("e", sb.ToString()); + } + + [Test] + public void ArrayStoreTest() + { + var store = new BytesStore(1); + + store.WriteValues(1, 2, 3); + Assert.True(new Byte[] { 1, 2, 3 }.SequenceEqual(store.Bytes.ToEnumerable())); + + store.Write(4); + Assert.True(new Byte[] { 1, 2, 3, 4 }.SequenceEqual(store.Bytes.ToEnumerable())); + + store.Clear(); + store.Write(5); + Assert.True(new Byte[] { 5 }.SequenceEqual(store.Bytes.ToEnumerable())); + } + } +} diff --git a/Editor/Tests/IWriteStreamTest.cs.meta b/Editor/Tests/IWriteStreamTest.cs.meta new file mode 100644 index 000000000..9b0920c01 --- /dev/null +++ b/Editor/Tests/IWriteStreamTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bda1e03d682e63749a6b114fd6cc0add +timeCreated: 1495517080 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json.meta b/Editor/Tests/Json.meta new file mode 100644 index 000000000..b1d1c9c5b --- /dev/null +++ b/Editor/Tests/Json.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7467ac74a97f50646b5e954a34682bae +folderAsset: yes +timeCreated: 1543250519 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json/JsonDiffTests.cs b/Editor/Tests/Json/JsonDiffTests.cs new file mode 100644 index 000000000..4dc6cedcc --- /dev/null +++ b/Editor/Tests/Json/JsonDiffTests.cs @@ -0,0 +1,71 @@ +using NUnit.Framework; +using System.Linq; + + +namespace UniJSON +{ + public class JsonDiffTests + { + [Test] + public void PathTest() + { + var json=@" +{ + ""a"": [ + { + ""aa"": 1 + } + ] +} +"; + var root = JsonParser.Parse(json); + + { + var it = root.Traverse().GetEnumerator(); + it.MoveNext(); Assert.AreEqual("/", it.Current.Pointer().ToString()); + it.MoveNext(); Assert.AreEqual("/a", it.Current.Pointer().ToString()); + it.MoveNext(); Assert.AreEqual("/a/0", it.Current.Pointer().ToString()); + it.MoveNext(); Assert.AreEqual("/a/0/aa", it.Current.Pointer().ToString()); + Assert.False(it.MoveNext()); + } + + { + var it = root.Traverse().GetEnumerator(); + + var f = new JsonFormatter(); + f.Serialize("JsonPath"); + + root.SetValue(Utf8String.From("/a"), f.GetStoreBytes()); + it.MoveNext(); Assert.AreEqual("/", it.Current.Pointer().ToString()); + it.MoveNext(); Assert.AreEqual("/a", it.Current.Pointer().ToString()); + Assert.False(it.MoveNext()); + } + } + + [Test] + public void DiffTest() + { + var a = @"{ +""a"": 1 +}"; + + var b = @"{ +}"; + + var diff = JsonParser.Parse(a).Diff(JsonParser.Parse(b)).ToArray(); + Assert.AreEqual(1, diff.Length); + } + +#if UNITY_EDITOR + [Test] + public void Vector3() + { + var src = new UnityEngine.Vector3(1, 2, 3); + var json = UnityEngine.JsonUtility.ToJson(src); + Assert.AreEqual("{\"x\":1.0,\"y\":2.0,\"z\":3.0}", json); + var dst = UnityEngine.JsonUtility.FromJson(json); + Assert.AreEqual(src, dst); + } +#endif + } +} diff --git a/Editor/Tests/Json/JsonDiffTests.cs.meta b/Editor/Tests/Json/JsonDiffTests.cs.meta new file mode 100644 index 000000000..43396090a --- /dev/null +++ b/Editor/Tests/Json/JsonDiffTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bafda51ddeeb2b84b920b119176499b8 +timeCreated: 1532154188 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json/JsonFormatterTest.cs b/Editor/Tests/Json/JsonFormatterTest.cs new file mode 100644 index 000000000..3643a2d5a --- /dev/null +++ b/Editor/Tests/Json/JsonFormatterTest.cs @@ -0,0 +1,47 @@ +using NUnit.Framework; +using UnityEngine; +using System.Linq; +using System.Text; + +namespace UniJSON +{ + public class JsonFormatterTests + { + [Test] + public void IndentTest() + { + var formatter = new JsonFormatter(2); + formatter.BeginMap(); + formatter.Key("a"); formatter.Value(1); + formatter.EndMap(); + + //var json = formatter.ToString(); + } + + [Test] + public void NullTest() + { + var bytes = Encoding.UTF8.GetBytes("null"); + var json = new JsonFormatter(); + json.Null(); + Assert.True(json.GetStoreBytes().ToEnumerable().SequenceEqual(bytes)); + } + + [Test] + public void BooleanTest() + { + { + var bytes = Encoding.UTF8.GetBytes("true"); + var json = new JsonFormatter(); + json.Value(true); + Assert.True(json.GetStoreBytes().ToEnumerable().SequenceEqual(bytes)); + } + { + var bytes = Encoding.UTF8.GetBytes("false"); + var json = new JsonFormatter(); + json.Value(false); + Assert.True(json.GetStoreBytes().ToEnumerable().SequenceEqual(bytes)); + } + } + } +} diff --git a/Editor/Tests/Json/JsonFormatterTest.cs.meta b/Editor/Tests/Json/JsonFormatterTest.cs.meta new file mode 100644 index 000000000..af3a70f6d --- /dev/null +++ b/Editor/Tests/Json/JsonFormatterTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3defb263d8925164683447a978248b1d +timeCreated: 1533569416 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json/JsonParserTest.cs b/Editor/Tests/Json/JsonParserTest.cs new file mode 100644 index 000000000..6bc856759 --- /dev/null +++ b/Editor/Tests/Json/JsonParserTest.cs @@ -0,0 +1,354 @@ +using NUnit.Framework; +using System; +using System.Linq; + + +namespace UniJSON +{ + public class JsonParserTest + { + [Test] + public void Tests() + { + { + var result = JsonParser.Parse("1"); + Assert.AreEqual(1, result.GetInt32()); + } + + { + var result = JsonParser.Parse("{ \"a\": { \"b\": 1 }}"); + Assert.True(result.ContainsKey("a")); + } + } + + [Test] + public void NullTest() + { + { + var node = JsonParser.Parse("null"); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(4, node.Value.Bytes.Count); + Assert.True(node.IsNull()); + } + } + + [Test] + public void BooleanTest() + { + { + var node = JsonParser.Parse("true"); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(4, node.Value.Bytes.Count); + Assert.True(node.IsBoolean()); + Assert.AreEqual(true, node.GetBoolean()); + Assert.Catch(typeof(FormatException), () => node.GetDouble()); + } + { + var node = JsonParser.Parse(" false "); + Assert.AreEqual(1, node.Value.Bytes.Offset); + Assert.AreEqual(5, node.Value.Bytes.Count); + Assert.True(node.IsBoolean()); + Assert.AreEqual(false, node.GetBoolean()); + } + } + + [Test] + public void NumberTest() + { + { + var node = JsonParser.Parse("1"); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(1, node.Value.Bytes.Count); + Assert.True(node.IsInteger()); + Assert.AreEqual(1, (int)node.GetDouble()); + Assert.Catch(typeof(DeserializationException), () => node.GetBoolean()); + } + { + var node = JsonParser.Parse(" 22 "); + Assert.AreEqual(1, node.Value.Bytes.Offset); + Assert.AreEqual(2, node.Value.Bytes.Count); + Assert.True(node.IsInteger()); + Assert.AreEqual(22, (int)node.GetDouble()); + } + { + var node = JsonParser.Parse(" 3.3 "); + Assert.AreEqual(1, node.Value.Bytes.Offset); + Assert.AreEqual(3, node.Value.Bytes.Count); + Assert.True(node.IsFloat()); + Assert.AreEqual(3, (int)node.GetDouble()); + Assert.AreEqual(3.3f, (float)node.GetDouble()); + } + { + var node = JsonParser.Parse(" -4.44444444444444444444 "); + Assert.True(node.IsFloat()); + Assert.AreEqual(-4, (int)node.GetDouble()); + Assert.AreEqual(-4.44444444444444444444, node.GetDouble()); + } + { + var node = JsonParser.Parse(" -5e-4 "); + Assert.True(node.IsFloat()); + Assert.AreEqual(0, (int)node.GetDouble()); + Assert.AreEqual(-5e-4, node.GetDouble()); + } + { + var node = JsonParser.Parse("NaN"); + Assert.True(node.IsFloat()); + Assert.AreEqual(Double.NaN, node.GetDouble()); + } + { + var node = JsonParser.Parse("Infinity"); + Assert.True(node.IsFloat()); + Assert.AreEqual(Double.PositiveInfinity, node.GetDouble()); + } + { + var node = JsonParser.Parse("-Infinity"); + Assert.True(node.IsFloat()); + Assert.AreEqual(Double.NegativeInfinity, node.GetDouble()); + } + } + + [Test] + public void StringTest() + { + { + var value = "hoge"; + var quoted = "\"hoge\""; + Assert.AreEqual(quoted, JsonString.Quote(value)); + var node = JsonParser.Parse(quoted); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(quoted.Length, node.Value.Bytes.Count); + Assert.True(node.IsString()); + Assert.AreEqual("hoge", node.GetString()); + } + + { + var value = "fuga\n hoge"; + var quoted = "\"fuga\\n hoge\""; + Assert.AreEqual(quoted, JsonString.Quote(value)); + var node = JsonParser.Parse(quoted); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(quoted.Length, node.Value.Bytes.Count); + Assert.True(node.IsString()); + Assert.AreEqual(value, node.GetString()); + } + } + + [Test] + public void StringEscapeTest() + { + { + var value = "\""; + var escaped = "\\\""; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "\\"; + var escaped = "\\\\"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "/"; + var escaped = "\\/"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "\b"; + var escaped = "\\b"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "\f"; + var escaped = "\\f"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "\n"; + var escaped = "\\n"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "\r"; + var escaped = "\\r"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + { + var value = "\t"; + var escaped = "\\t"; + Assert.AreEqual(escaped, JsonString.Escape(value)); + Assert.AreEqual(value, JsonString.Unescape(escaped)); + } + } + + [Test] + public void ObjectTest() + { + { + var json = "{}"; + var node = JsonParser.Parse(json); + Assert.AreEqual(0, node.Value.Bytes.Offset); + + Assert.AreEqual(2, node.Value.Bytes.Count); + + Assert.True(node.IsMap()); + Assert.AreEqual(0, node.ObjectItems().Count()); + } + + { + var json = "{\"key\":\"value\"}"; + var node = JsonParser.Parse(json); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(json.Length, node.Value.Bytes.Count); + Assert.True(node.IsMap()); + + var it = node.ObjectItems().GetEnumerator(); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("key", it.Current.Key.GetString()); + Assert.AreEqual("value", it.Current.Value.GetString()); + + Assert.IsFalse(it.MoveNext()); + } + + { + var json = "{\"key\":\"value\"}"; + var node = JsonParser.Parse(json); + Assert.AreEqual(0, node.Value.Bytes.Offset); + Assert.AreEqual(json.Length, node.Value.Bytes.Count); + Assert.True(node.IsMap()); + + var it = node.ObjectItems().GetEnumerator(); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("key", it.Current.Key.GetString()); + Assert.AreEqual("value", it.Current.Value.GetString()); + + Assert.IsFalse(it.MoveNext()); + } + } + + [Test] + public void NestedObjectTest() + { + { + var json = "{\"key\":{ \"nestedKey\": \"nestedValue\" }, \"key2\": { \"nestedKey2\": \"nestedValue2\" } }"; + var node = JsonParser.Parse(json); + Assert.True(node.IsMap()); + + { + var it = node.ObjectItems().GetEnumerator(); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("key", it.Current.Key.GetString()); + Assert.True(it.Current.Value.IsMap()); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("key2", it.Current.Key.GetString()); + Assert.True(it.Current.Value.IsMap()); + + Assert.IsFalse(it.MoveNext()); + } + + var nested = node["key2"]; + + { + var it = nested.ObjectItems().GetEnumerator(); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("nestedKey2", it.Current.Key.GetString()); + Assert.AreEqual("nestedValue2", it.Current.Value.GetString()); + + Assert.IsFalse(it.MoveNext()); + } + + Assert.AreEqual("nestedValue2", node["key2"]["nestedKey2"].GetString()); + } + } + + [Test] + public void ArrayTest() + { + { + var json = "[]"; + var node = JsonParser.Parse(json); + Assert.AreEqual(0, node.Value.Bytes.Offset); + + //Assert.Catch(() => { var result = node.Value.Bytes.Count; }, "raise exception"); + Assert.AreEqual(2, node.Value.Bytes.Count); + + Assert.True(node.IsArray()); + + Assert.AreEqual("[\n]", node.ToString(" ")); + } + + { + var json = "[1,2,3]"; + var node = JsonParser.Parse(json); + Assert.AreEqual(0, node.Value.Bytes.Offset); + + //Assert.Catch(() => { var result = node.Value.Bytes.Count; }, "raise exception"); + + Assert.True(node.IsArray()); + Assert.AreEqual(1, node[0].GetDouble()); + Assert.AreEqual(2, node[1].GetDouble()); + Assert.AreEqual(3, node[2].GetDouble()); + + Assert.AreEqual("[\n 1,\n 2,\n 3\n]", node.ToString(" ")); + } + + { + var json = "[\"key\",1]"; + var node = JsonParser.Parse(json); + Assert.AreEqual(0, node.Value.Bytes.Offset); + + //Assert.Catch(() => { var result = node.Value.Bytes.Count; }, "raise exception"); + Assert.AreEqual(json.Length, node.Value.Bytes.Count); + + Assert.True(node.IsArray()); + + var it = node.ArrayItems().GetEnumerator(); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("key", it.Current.GetString()); + + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual(1, it.Current.GetDouble()); + + Assert.IsFalse(it.MoveNext()); + + Assert.AreEqual("key", node[0].GetString()); + Assert.AreEqual(1, node[1].GetDouble()); + + Assert.AreEqual("[\n \"key\",\n 1\n]", node.ToString(" ")); + } + } + + [Test] + public void ParseTest() + { + var json = "{"; + Assert.Catch(typeof(ParserException), () => JsonParser.Parse(json)); + } + + [Test] + public void Utf8Test() + { + JsonParser.Parse("\"5\""); + } + + [Test] + public void TimeTest() + { + var f = new JsonFormatter(); + f.Value(new DateTimeOffset()); + + Assert.AreEqual("\"0001-01-01T00:00:00Z\"", new Utf8String(f.GetStoreBytes()).ToString()); + } + } +} diff --git a/Editor/Tests/Json/JsonParserTest.cs.meta b/Editor/Tests/Json/JsonParserTest.cs.meta new file mode 100644 index 000000000..d5a14a07f --- /dev/null +++ b/Editor/Tests/Json/JsonParserTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4af58e17f98c9a141b9fef25dabbd9ce +timeCreated: 1495517074 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json/JsonSerializerTests.cs b/Editor/Tests/Json/JsonSerializerTests.cs new file mode 100644 index 000000000..f603fc08b --- /dev/null +++ b/Editor/Tests/Json/JsonSerializerTests.cs @@ -0,0 +1,152 @@ +#pragma warning disable 0649 +using System; +using NUnit.Framework; +using System.Collections.Generic; + + +namespace UniJSON +{ + public class JsonSerializerTests + { + struct Point + { + public float X; + public float Y; + + public float[] Vector; + + public override string ToString() + { + return string.Format("{{X={0}, Y={1}, {2}}}", X, Y, Vector); + } + } + + enum HogeFuga + { + Hoge, + Fuga, + } + + struct EnumTest + { + public HogeFuga EnumDefault; + + [JsonSchema(EnumSerializationType =EnumSerializationType.AsInt)] + public HogeFuga EnumAsInt; + + [JsonSchema(EnumSerializationType = EnumSerializationType.AsString)] + public HogeFuga EnumAsString; + + [JsonSchema(EnumSerializationType = EnumSerializationType.AsLowerString)] + public HogeFuga EnumAsLowerString; + } + + #region Serializer + static void SerializeValue(T value, string json) + { + var b = new BytesStore(); + var f = new JsonFormatter(b); + + f.Serialize(value); + Assert.AreEqual(json, new Utf8String(b.Bytes).ToString()); + } + + [Test] + public void JsonSerializerTest() + { + SerializeValue(1, "1"); + SerializeValue(1.1f, "1.1"); + SerializeValue(1.2, "1.2"); + SerializeValue(Double.NaN, "NaN"); + SerializeValue(Double.PositiveInfinity, "Infinity"); + SerializeValue(Double.NegativeInfinity, "-Infinity"); + SerializeValue(true, "true"); + SerializeValue(false, "false"); + SerializeValue("ascii", "\"ascii\""); + + SerializeValue(new[] { 1 }, "[1]"); + SerializeValue(new[] { 1.1f }, "[1.1]"); + SerializeValue(new[] { 1.2 }, "[1.2]"); + SerializeValue(new[] { true, false }, "[true,false]"); + SerializeValue(new[] { "ascii" }, "[\"ascii\"]"); + SerializeValue(new List { 1 }, "[1]"); + //SerializeValue(new object[] { null, 1, "a" }, "[null,1,\"a\"]"); + + SerializeValue(new Dictionary { }, "{}"); + SerializeValue(new Dictionary { { "a", 1 } }, "{\"a\":1}"); + SerializeValue(new Dictionary { { "a", + new Dictionary{ + } } }, "{\"a\":{}}"); + + SerializeValue(new Point { X = 1 }, "{\"X\":1,\"Y\":0}"); + + SerializeValue(HogeFuga.Fuga, "1"); + + SerializeValue(new EnumTest(), "{\"EnumDefault\":0,\"EnumAsInt\":0,\"EnumAsString\":\"Hoge\",\"EnumAsLowerString\":\"hoge\"}"); + } + + [Test] + public void KeyValue() + { + var p = new Point + { + X = 1, + Vector = new float[] { 1, 2, 3 } + }; + + var f = new JsonFormatter(); + f.BeginMap(); + f.KeyValue(() => p.Vector); + f.EndMap(); + + var json = JsonParser.Parse(new Utf8String(f.GetStoreBytes())); + + Assert.AreEqual(1, json.GetObjectCount()); + Assert.AreEqual(1, json["Vector"][0].GetInt32()); + } + #endregion + + #region Deserialize + static void DeserializeValue(T value, string json) + { + var parsed = JsonParser.Parse(json); + + var t = default(T); + parsed.Deserialize(ref t); + + Assert.AreEqual(value, t); + } + + [Test] + public void JsonDeserializerTest() + { + DeserializeValue(1, "1"); + DeserializeValue(1.1f, "1.1"); + DeserializeValue(1.2, "1.2"); + DeserializeValue(true, "true"); + DeserializeValue(false, "false"); + DeserializeValue("ascii", "\"ascii\""); + + DeserializeValue(new[] { 1 }, "[1]"); + DeserializeValue(new[] { 1.1f }, "[1.1]"); + DeserializeValue(new[] { 1.2 }, "[1.2]"); + DeserializeValue(new[] { true, false }, "[true,false]"); + DeserializeValue(new[] { "ascii" }, "[\"ascii\"]"); + DeserializeValue(new List { 1 }, "[1]"); + //DeserializeValue(new object[] { null, 1, "a" }, "[null,1,\"a\"]"); + + DeserializeValue(new Dictionary { }, "{}"); + DeserializeValue(new Dictionary { { "a", 1 } }, "{\"a\":1}"); + DeserializeValue(new Dictionary { { "a", + new Dictionary{ + } } }, "{\"a\":{}}"); + + DeserializeValue(new Point { X = 1 }, "{\"X\":1,\"Y\":0}"); + + DeserializeValue(HogeFuga.Fuga, "1"); + + DeserializeValue(new EnumTest(), "{\"EnumDefault\":0,\"EnumAsInt\":0,\"EnumAsString\":\"Hoge\",\"EnumAsLowerString\":\"hoge\"}"); + } + #endregion + } +} diff --git a/Editor/Tests/Json/JsonSerializerTests.cs.meta b/Editor/Tests/Json/JsonSerializerTests.cs.meta new file mode 100644 index 000000000..2521c928d --- /dev/null +++ b/Editor/Tests/Json/JsonSerializerTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b08b704c97f3bc54c8469f9f1822432d +timeCreated: 1543256597 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json/JsonValueTests.cs b/Editor/Tests/Json/JsonValueTests.cs new file mode 100644 index 000000000..fbfbced1e --- /dev/null +++ b/Editor/Tests/Json/JsonValueTests.cs @@ -0,0 +1,41 @@ +using NUnit.Framework; +using System; +using System.Linq; + +namespace UniJSON +{ + public class JsonValueTests + { + // TODO: Add tests for values which have other types + + [Test] + public void NaNTest() + { + { + var v = new JsonValue(Utf8String.From("NaN"), ValueNodeType.NaN, -1); + Assert.AreEqual("NaN", v.ToString()); + Assert.AreEqual(Double.NaN, v.GetValue()); + } + } + + [Test] + public void InfinityTest() + { + { + var v = new JsonValue(Utf8String.From("Infinity"), ValueNodeType.Infinity, -1); + Assert.AreEqual("Infinity", v.ToString()); + Assert.AreEqual(Double.PositiveInfinity, v.GetValue()); + } + } + + [Test] + public void MinusInfinityTest() + { + { + var v = new JsonValue(Utf8String.From("-Infinity"), ValueNodeType.MinusInfinity, -1); + Assert.AreEqual("-Infinity", v.ToString()); + Assert.AreEqual(Double.NegativeInfinity, v.GetValue()); + } + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Json/JsonValueTests.cs.meta b/Editor/Tests/Json/JsonValueTests.cs.meta new file mode 100644 index 000000000..7c64a542e --- /dev/null +++ b/Editor/Tests/Json/JsonValueTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b0dfab85f59470d8cba21b351fa766b +timeCreated: 1545750553 \ No newline at end of file diff --git a/Editor/Tests/Json/SchemaTests.cs b/Editor/Tests/Json/SchemaTests.cs new file mode 100644 index 000000000..7f1c2e8c0 --- /dev/null +++ b/Editor/Tests/Json/SchemaTests.cs @@ -0,0 +1,134 @@ +#pragma warning disable 0649 +using NUnit.Framework; + + +namespace UniJSON +{ + public class SchemaTests + { + /// + /// http://json-schema.org/examples.html + /// + [JsonSchema(Title="Person")] + public class Person + { + [JsonSchema(Required = true)] + public string firstName; + + [JsonSchema(Required = true)] + public string lastName; + + [JsonSchema(Description = "Age in years", Minimum = 0)] + public int age; + } + + [Test] + public void CreateFromClass() + { + var s = JsonSchema.FromType(); + Assert.AreEqual("Person", s.Title); + + var v = s.Validator as JsonObjectValidator; + Assert.AreEqual("Age in years", v.Properties["age"].Description); + Assert.AreEqual(new[] { "firstName", "lastName" }, v.Required); + + var f = new JsonFormatter(2); + s.ToJson(f); + var json = f.ToString(); + + var parsed = JsonParser.Parse(json); + Assert.AreEqual(0, parsed["properties"]["age"]["minimum"].GetInt32()); + } + + public enum ProjectionType + { + Perspective, + Orthographic + } + + class EnumStringTest + { + [JsonSchema(EnumSerializationType =EnumSerializationType.AsLowerString)] + public ProjectionType type; + } + + class EnumIntTest + { + [JsonSchema(EnumSerializationType = EnumSerializationType.AsInt)] + public ProjectionType type; + } + + [Test] + public void TestEnumAsString() + { + var json = @" +{ + ""type"": ""object"", + ""properties"": { + + ""type"": { + + ""anyOf"": [ + { + ""enum"": [ ""perspective"" ] + }, + { + ""enum"": [ ""orthographic"" ] + }, + { + ""type"": ""string"" + } + ] + + } + + } +} +"; + + var fromJson = new JsonSchema(); + fromJson.Parse(null, JsonParser.Parse(json), "enum test"); + + var fromType = JsonSchema.FromType(); + + Assert.AreEqual(fromJson, fromType); + } + + [Test] + public void TestEnumAsInt() + { + var json = @" +{ + ""type"": ""object"", + ""properties"": { + + ""type"": { + + ""anyOf"": [ + { + ""enum"": [ 0 ] + }, + { + ""enum"": [ 1 ] + }, + { + ""type"": ""integer"" + } + ] + + } + + } +} +"; + + var fromJson = new JsonSchema(); + fromJson.Parse(null, JsonParser.Parse(json), "enum test"); + + var fromType = JsonSchema.FromType(); + + Assert.AreEqual(fromJson, fromType); + } + + } +} diff --git a/Editor/Tests/Json/SchemaTests.cs.meta b/Editor/Tests/Json/SchemaTests.cs.meta new file mode 100644 index 000000000..c11d56f02 --- /dev/null +++ b/Editor/Tests/Json/SchemaTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d4dfd16b1b05c8640898b955df61c51b +timeCreated: 1526055801 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Json/ValidatorTests.cs b/Editor/Tests/Json/ValidatorTests.cs new file mode 100644 index 000000000..de70a183b --- /dev/null +++ b/Editor/Tests/Json/ValidatorTests.cs @@ -0,0 +1,251 @@ +using NUnit.Framework; +using System.Collections.Generic; + +namespace UniJSON +{ + public class ValidatorTests + { + [Test] + public void IntValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var v = new JsonIntValidator(); + v.Maximum = 0; + Assert.NotNull(v.Validate(c, 1)); + Assert.Null(v.Validate(c, 0)); + Assert.Null(v.Validate(c, -1)); + } + { + var v = new JsonIntValidator(); + v.Maximum = 0; + v.ExclusiveMaximum = true; + Assert.NotNull(v.Validate(c, 1)); + Assert.NotNull(v.Validate(c, 0)); + Assert.Null(v.Validate(c, -1)); + } + { + var v = new JsonIntValidator(); + v.Minimum = 0; + Assert.Null(v.Validate(c, 1)); + Assert.Null(v.Validate(c, 0)); + Assert.NotNull(v.Validate(c, -1)); + } + { + var v = new JsonIntValidator(); + v.Minimum = 0; + v.ExclusiveMinimum = true; + Assert.Null(v.Validate(c, 1)); + Assert.NotNull(v.Validate(c, 0)); + Assert.NotNull(v.Validate(c, -1)); + } + { + var v = new JsonIntValidator(); + v.MultipleOf = 4; + Assert.Null(v.Validate(c, 4)); + Assert.NotNull(v.Validate(c, 5)); + } + + Assert.True(c.IsEmpty()); + } + + [Test] + public void NumberValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var v = new JsonNumberValidator(); + v.Maximum = 0.1; + Assert.NotNull(v.Validate(c, 1)); + Assert.Null(v.Validate(c, 0.1)); + Assert.Null(v.Validate(c, -1)); + } + { + var v = new JsonNumberValidator(); + v.Maximum = 0.1; + v.ExclusiveMaximum = true; + Assert.NotNull(v.Validate(c, 1)); + Assert.NotNull(v.Validate(c, 0.1)); + Assert.Null(v.Validate(c, -1)); + } + { + var v = new JsonNumberValidator(); + v.Minimum = 0.1; + Assert.Null(v.Validate(c, 1)); + Assert.Null(v.Validate(c, 0.1)); + Assert.NotNull(v.Validate(c, -1)); + } + { + var v = new JsonNumberValidator(); + v.Minimum = 0.1; + v.ExclusiveMinimum = true; + Assert.Null(v.Validate(c, 1)); + Assert.NotNull(v.Validate(c, 0.1)); + Assert.NotNull(v.Validate(c, -1)); + } + + Assert.True(c.IsEmpty()); + } + + [Test] + public void BoolValidator() + { + // ??? + } + + [Test] + public void StringValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var v = new JsonStringValidator(); + v.MinLength = 1; + Assert.Null(v.Validate(c, "a")); + Assert.NotNull(v.Validate(c, "")); + } + { + var v = new JsonStringValidator(); + v.MaxLength = 1; + Assert.Null(v.Validate(c, "a")); + Assert.NotNull(v.Validate(c, "ab")); + } + { + var v = new JsonStringValidator(); + v.Pattern = new System.Text.RegularExpressions.Regex("abc"); + Assert.Null(v.Validate(c, "abc")); + Assert.NotNull(v.Validate(c, "ab")); + } + { + var v = new JsonStringValidator(); + v.Pattern = new System.Text.RegularExpressions.Regex("ab+"); + Assert.Null(v.Validate(c, "abb")); + Assert.Null(v.Validate(c, "ab")); + Assert.NotNull(v.Validate(c, "a")); + } + + Assert.True(c.IsEmpty()); + } + + [Test] + public void StringEnumValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var v = JsonStringEnumValidator.Create(new string[] { "a", "b" }, EnumSerializationType.AsString); + Assert.Null(v.Validate(c, "a")); + Assert.NotNull(v.Validate(c, "c")); + } + + Assert.True(c.IsEmpty()); + } + + [Test] + public void IntEnumValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var v = new JsonIntEnumValidator(); + v.Values = new int[] { 1, 2 }; + Assert.Null(v.Validate(c, 1)); + Assert.NotNull(v.Validate(c, 3)); + } + + Assert.True(c.IsEmpty()); + } + + [Test] + public void ArrayValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var v = new JsonArrayValidator(); + v.MaxItems = 1; + Assert.Null(v.Validate(c, new object[] { 0 })); + Assert.NotNull(v.Validate(c, new object[] { 0, 1 })); + } + + { + var v = new JsonArrayValidator(); + v.MinItems = 1; + Assert.Null(v.Validate(c, new object[] { 0 })); + Assert.NotNull(v.Validate(c, new object[] { })); + } + + Assert.True(c.IsEmpty()); + } + + class Hoge + { + [JsonSchema(Required = true, Minimum = 1)] + public int Value; + } + + [Test] + public void ObjectValidator() + { + var c = new JsonSchemaValidationContext("test"); + { + var s = JsonSchema.FromType(); + Assert.Null(s.Validator.Validate(c, new Hoge { Value = 1 })); + Assert.NotNull(s.Validator.Validate(c, new Hoge { Value = 0 })); + } + + Assert.True(c.IsEmpty()); + } + + [Test] + public void DictionaryValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var s = JsonSchema.FromType>(); + Assert.True(s.Validator is JsonDictionaryValidator); + + var v = s.Validator as JsonDictionaryValidator; + v.MinProperties = 1; + v.AdditionalProperties = JsonSchema.FromType(); + (v.AdditionalProperties.Validator as JsonIntValidator).Minimum = 0; + + Assert.Null(s.Validator.Validate(c, new Dictionary + { + {"POSITION", 0} + })); + + var result = s.Validator.Validate(c, new Dictionary + { + {"POSITION", -1} + }); + Assert.NotNull(result); + } + + Assert.True(c.IsEmpty()); + } + + class HasDictionary + { + public Dictionary primitiveProperties = new Dictionary(); + // TODO: fix + // public Dictionary nestedProperties = new Dictionary(); + } + + [Test] + public void HasDictionaryObjectValidator() + { + var c = new JsonSchemaValidationContext("test"); + + { + var s = JsonSchema.FromType(); + Assert.Null(s.Validator.Validate(c, new HasDictionary())); + } + + Assert.True(c.IsEmpty()); + } + } +} diff --git a/Editor/Tests/Json/ValidatorTests.cs.meta b/Editor/Tests/Json/ValidatorTests.cs.meta new file mode 100644 index 000000000..66ad4caea --- /dev/null +++ b/Editor/Tests/Json/ValidatorTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 16d778a50d1c9374894ef42f892210dd +timeCreated: 1531900562 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack.meta b/Editor/Tests/MsgPack.meta new file mode 100644 index 000000000..187193c44 --- /dev/null +++ b/Editor/Tests/MsgPack.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0bcf0d9b7cba67c42ba04c530aa7cd38 +folderAsset: yes +timeCreated: 1540812199 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/ArrayTest.cs b/Editor/Tests/MsgPack/ArrayTest.cs new file mode 100644 index 000000000..2710de50e --- /dev/null +++ b/Editor/Tests/MsgPack/ArrayTest.cs @@ -0,0 +1,92 @@ +using NUnit.Framework; +using System; +using System.Linq; + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class ArrayTest + { + [Test] + public void fix_array() + { + var f = new MsgPackFormatter(); + // Object[] not supported + f.Serialize(new[] { 0, 1, false, (Object)null }); + var _bytes = f.GetStoreBytes(); + var bytes = _bytes.Array.Skip(_bytes.Offset).Take(_bytes.Count).ToArray(); + + Assert.AreEqual(new Byte[]{ + (Byte)MsgPackType.FIX_ARRAY_0x4, + (Byte)MsgPackType.POSITIVE_FIXNUM, + (Byte)MsgPackType.POSITIVE_FIXNUM_0x01, + (Byte)MsgPackType.FALSE, + (Byte)MsgPackType.NIL + }, bytes); + + var parsed = MsgPackParser.Parse(bytes); + + Assert.AreEqual(4, parsed.GetArrayCount()); + Assert.AreEqual(0, parsed[0].GetValue()); + Assert.AreEqual(1, parsed[1].GetValue()); + Assert.False((Boolean)parsed[2].GetValue()); + Assert.AreEqual(null, parsed[3].GetValue()); + } + + [Test] + public void array16() + { + var f = new MsgPackFormatter(); + var data = Enumerable.Range(0, 20).Select(x => (Object)x).ToArray(); + f.Serialize(data); + var bytes = f.GetStoreBytes(); + + var value = MsgPackParser.Parse(bytes); + Assert.IsTrue(value.IsArray()); + Assert.AreEqual(20, value.GetArrayCount()); + for (int i = 0; i < 20; ++i) + { + Assert.AreEqual(i, value[i].GetValue()); + } + } + + [Test] + public void array129() + { + { + var i128 = Enumerable.Range(0, 128).ToArray(); + var f = new MsgPackFormatter(); + f.Serialize(i128); + var bytes128 = f.GetStoreBytes(); + var deserialized = MsgPackParser.Parse(bytes128); + Assert.AreEqual(128, deserialized.GetArrayCount()); + for (int i = 0; i < i128.Length; ++i) + { + Assert.AreEqual(i128[i], deserialized[i].GetValue()); + } + } + + { + var i129 = Enumerable.Range(0, 129).ToArray(); + var f = new MsgPackFormatter(); + f.Serialize(i129); + var bytes129 = f.GetStoreBytes(); + var deserialized = MsgPackParser.Parse(bytes129); + Assert.AreEqual(129, deserialized.GetArrayCount()); + for (int i = 0; i < i129.Length; ++i) + { + Assert.AreEqual(i129[i], deserialized[i].GetValue()); + } + } + } + + [Test] + public void ReadTest() + { + var data = new int[] { -108, 0, 1, -90, 108, 111, 103, 103, 101, 114, -110, -91, 69, 114, 114, 111, 114, -94, 101, 50 } + .Select(x => (Byte)x).ToArray(); + var parsed = MsgPackParser.Parse(data); + Assert.True(parsed.IsArray()); + } + } +} diff --git a/Editor/Tests/MsgPack/ArrayTest.cs.meta b/Editor/Tests/MsgPack/ArrayTest.cs.meta new file mode 100644 index 000000000..733ee7e6e --- /dev/null +++ b/Editor/Tests/MsgPack/ArrayTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4b485b0360ebfd246ac90bbe8ad1895b +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/BooleanTest.cs b/Editor/Tests/MsgPack/BooleanTest.cs new file mode 100644 index 000000000..4cdce4a88 --- /dev/null +++ b/Editor/Tests/MsgPack/BooleanTest.cs @@ -0,0 +1,50 @@ +using NUnit.Framework; +using System; + + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class BooleanTest + { + [Test] + public void nil() + { + { + var f = new MsgPackFormatter(); + f.Null(); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[] { 0xC0 }, bytes.ToEnumerable()); + + var parsed = MsgPackParser.Parse(bytes); + Assert.True(parsed.IsNull()); + } + } + + [Test] + public void True() + { + var f = new MsgPackFormatter(); + f.Value(true); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[] { 0xC3 }, bytes.ToEnumerable()); + + var value = MsgPackParser.Parse(bytes); + var j = value.GetBoolean(); + Assert.AreEqual(true, j); + } + + [Test] + public void False() + { + var f = new MsgPackFormatter(); + f.Value(false); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[] { 0xC2 }, bytes.ToEnumerable()); + + var value = MsgPackParser.Parse(bytes); + var j = value.GetBoolean(); + Assert.AreEqual(false, j); + } + } +} diff --git a/Editor/Tests/MsgPack/BooleanTest.cs.meta b/Editor/Tests/MsgPack/BooleanTest.cs.meta new file mode 100644 index 000000000..d179af7c2 --- /dev/null +++ b/Editor/Tests/MsgPack/BooleanTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d0f19e48b365cd446982ed0b7ba6251e +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/FloatTest.cs b/Editor/Tests/MsgPack/FloatTest.cs new file mode 100644 index 000000000..e8b226d3d --- /dev/null +++ b/Editor/Tests/MsgPack/FloatTest.cs @@ -0,0 +1,50 @@ +using NUnit.Framework; +using System; +using System.Linq; + + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class FloatTest + { + [Test] + public void Float32() + { + var i = 1.1f; + var float_be = new byte[] + { + (Byte)MsgPackType.FLOAT, 0x3f, 0x8c, 0xcc, 0xcd + }; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + var value = MsgPackParser.Parse(bytes); + var body = value.Value.Bytes; + Assert.AreEqual(float_be, body.ToEnumerable().ToArray()); + + Assert.AreEqual(i, value.GetValue()); + } + + [Test] + public void Float64() + { + var i = 1.1; + var double_be = new Byte[]{ + (Byte)MsgPackType.DOUBLE, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, + }; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + var value = MsgPackParser.Parse(bytes); + var body = value.Value.Bytes; + Assert.AreEqual(double_be, body.ToEnumerable().ToArray()); + + Assert.AreEqual(i, value.GetValue()); + } + } +} diff --git a/Editor/Tests/MsgPack/FloatTest.cs.meta b/Editor/Tests/MsgPack/FloatTest.cs.meta new file mode 100644 index 000000000..b2893722d --- /dev/null +++ b/Editor/Tests/MsgPack/FloatTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 51cdc6be3b73a34429cae41cd020c71c +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/IntTest.cs b/Editor/Tests/MsgPack/IntTest.cs new file mode 100644 index 000000000..d6222bea0 --- /dev/null +++ b/Editor/Tests/MsgPack/IntTest.cs @@ -0,0 +1,220 @@ +using NUnit.Framework; +using System; + + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class IntTest + { + [Test] + public void positive_fixnum() + { + for (Byte i = 0; i < 128; ++i) + { + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[] { i }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void negative_fixnum() + { + for (SByte i = -32; i < 0; ++i) + { + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void uint8() + { + { + Byte i = 0x7F + 20; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[]{ + 0xcc, 0x93, + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void cast_large_type() + { + { + Byte i = 0x7F + 20; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[]{ + 0xcc, 0x93, + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void uint16() + { + { + UInt16 i = 0xFF + 20; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[]{ + 0xcd, 0x01, 0x13 + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void uint32() + { + { + UInt32 i = 0xFFFF + 20; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[]{ + 0xce, 0x00, 0x01, 0x00, 0x13 + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void uint64() + { + { + UInt64 i = 0xFFFFFFFF; + i += 20; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[]{ + 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13 + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void int8() + { + { + SByte i = -64; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + Assert.AreEqual(new Byte[]{ + 0xd0, 0xc0, + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void int128Test() + { + int i = 128; + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + Assert.AreEqual(new Byte[]{ + 0xcc, 0x80, + }, bytes.ToEnumerable()); + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + + [Test] + public void int16() + { + { + Int16 i = -150; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + Assert.AreEqual(new Byte[]{ + 0xd1, 0xFF, 0x6a + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void int32() + { + { + Int32 i = -35000; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + Assert.AreEqual(new Byte[]{ + 0xd2, 0xff, 0xff, 0x77, 0x48 + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + + [Test] + public void int64() + { + { + Int64 i = -2147483650; + + var f = new MsgPackFormatter(); + f.Value(i); + var bytes = f.GetStoreBytes(); + + Assert.AreEqual(new Byte[]{ + 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe + }, bytes.ToEnumerable()); + + var j = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(i, j); + } + } + } +} diff --git a/Editor/Tests/MsgPack/IntTest.cs.meta b/Editor/Tests/MsgPack/IntTest.cs.meta new file mode 100644 index 000000000..c2800a7fd --- /dev/null +++ b/Editor/Tests/MsgPack/IntTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8d6f5e40bc0825b449887d877c0ad5c5 +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/MapTest.cs b/Editor/Tests/MsgPack/MapTest.cs new file mode 100644 index 000000000..401de80d0 --- /dev/null +++ b/Editor/Tests/MsgPack/MapTest.cs @@ -0,0 +1,120 @@ +using NUnit.Framework; +using System; +using System.IO; +using System.Linq; + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class MapTest + { + [Test] + public void fix_map() + { + var f = new MsgPackFormatter(); + f.BeginMap(2); + f.Key("0"); f.Value(1); + f.Key("2"); f.Value(3); + f.EndMap(); + var bytes = + f.GetStoreBytes(); + ; + + Assert.AreEqual(new Byte[]{ + 0x82, // map2 + + 0xa1, 0x30, // "0" + 0x01, // 1 + + 0xa1, 0x32, // "2" + 0x03 // 3 + }, bytes.ToEnumerable()); + + var value = MsgPackParser.Parse(bytes); + + Assert.AreEqual(2, value.GetObjectCount()); + Assert.AreEqual(1, value["0"].GetValue()); + Assert.AreEqual(3, value["2"].GetValue()); + } + + [Test] + public void map16() + { + var w = new MsgPackFormatter(); + int size = 18; + w.BeginMap(size); + for (int i = 0; i < size; ++i) + { + w.Value(i.ToString()); + w.Value(i + 5); + } + var bytes = w.GetStoreBytes().ToEnumerable().ToArray(); + + + var expected = new Byte[]{ + 0xde, // map18 + 0x0, 0x12, // 18 + + 0xa1, 0x30, // "0" + 0x5, + + 0xa1, 0x31, // "1" + 0x6, + + 0xa1, 0x32, // "2" + 0x7, + + 0xa1, 0x33, // "3" + 0x8, + + 0xa1, 0x34, // "4" + 0x9, + + 0xa1, 0x35, // "5" + 0xa, + + 0xa1, 0x36, // "6" + 0xb, + + 0xa1, 0x37, // "7" + 0xc, + + 0xa1, 0x38, // "8" + 0xd, + + 0xa1, 0x39, // "9" + 0xe, + + 0xa2, 0x31, 0x30, // "10" + 0xf, + + 0xa2, 0x31, 0x31, // "11" + 0x10, + + 0xa2, 0x31, 0x32, // "12" + 0x11, + + 0xa2, 0x31, 0x33, // "13" + 0x12, + + 0xa2, 0x31, 0x34, // "14" + 0x13, + + 0xa2, 0x31, 0x35, // "15" + 0x14, + + 0xa2, 0x31, 0x36, // "16" + 0x15, + + 0xa2, 0x31, 0x37, // "17", + 0x16 + }; + + Assert.AreEqual(expected, bytes); + + var value = MsgPackParser.Parse(bytes); + + Assert.AreEqual(15, value["10"].GetValue()); + } + } +} diff --git a/Editor/Tests/MsgPack/MapTest.cs.meta b/Editor/Tests/MsgPack/MapTest.cs.meta new file mode 100644 index 000000000..7c87a562d --- /dev/null +++ b/Editor/Tests/MsgPack/MapTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 87a626e93589db14fbe4526c9880b110 +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/RawTest.cs b/Editor/Tests/MsgPack/RawTest.cs new file mode 100644 index 000000000..4629e7841 --- /dev/null +++ b/Editor/Tests/MsgPack/RawTest.cs @@ -0,0 +1,34 @@ +using NUnit.Framework; +using System; +using System.Linq; + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class RawTest + { + [Test] + public void fix_raw() + { + var src = new Byte[] { 0, 1, 2 }; + var f = new MsgPackFormatter(); + f.Value(src); + var bytes = f.GetStoreBytes(); + + var v = MsgPackParser.Parse(bytes).Value.GetBody(); + Assert.True(src.SequenceEqual(v.ToEnumerable())); + } + + [Test] + public void raw16() + { + var src = Enumerable.Range(0, 50).Select(x => (Byte)x).ToArray(); + var f = new MsgPackFormatter(); + f.Value(src); + var bytes = f.GetStoreBytes(); + + var v = MsgPackParser.Parse(bytes).Value.GetBody(); + Assert.True(src.SequenceEqual(v.ToEnumerable())); + } + } +} diff --git a/Editor/Tests/MsgPack/RawTest.cs.meta b/Editor/Tests/MsgPack/RawTest.cs.meta new file mode 100644 index 000000000..402252f92 --- /dev/null +++ b/Editor/Tests/MsgPack/RawTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 331bd613923afe5438ef4ff3a59fc5b3 +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/StringTest.cs b/Editor/Tests/MsgPack/StringTest.cs new file mode 100644 index 000000000..1bc8accd1 --- /dev/null +++ b/Editor/Tests/MsgPack/StringTest.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using System; +using System.Linq; + +namespace UniJSON.MsgPack +{ + [TestFixture] + public class StringTest + { + [Test] + public void str() + { + var f = new MsgPackFormatter(); + f.Value("文字列"); + var bytes = f.GetStoreBytes(); + + var v = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual("文字列", v); + } + + [Test] + public void fix_str() + { + for (int i = 1; i < 32; ++i) + { + var str = String.Join("", Enumerable.Range(0, i).Select(_ => "0").ToArray()); + var f = new MsgPackFormatter(); + f.Value(str); + var bytes = f.GetStoreBytes(); + + var value = MsgPackParser.Parse(bytes); + Assert.AreEqual(i, ((String)value.GetValue()).Length); + } + } + } +} diff --git a/Editor/Tests/MsgPack/StringTest.cs.meta b/Editor/Tests/MsgPack/StringTest.cs.meta new file mode 100644 index 000000000..438025580 --- /dev/null +++ b/Editor/Tests/MsgPack/StringTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3942810073614d946a76d87cbbfb222c +timeCreated: 1540812276 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/MsgPack/TimeTests.cs b/Editor/Tests/MsgPack/TimeTests.cs new file mode 100644 index 000000000..35b90cd36 --- /dev/null +++ b/Editor/Tests/MsgPack/TimeTests.cs @@ -0,0 +1,50 @@ +using NUnit.Framework; +using System; + + +namespace UniJSON.MsgPack +{ + public class TimeTests + { + [Test] + public void TimeTest() + { + var f = new MsgPackFormatter(); + + { + f.GetStore().Clear(); + var time = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); + f.Value(time); + + var bytes = f.GetStoreBytes().ArrayOrCopy(); + unchecked + { + Assert.AreEqual(new byte[] + { + (byte)MsgPackType.FIX_EXT_4, (byte)-1, 0, 0, 0, 0 + }, bytes); + } + var parsed = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(time, parsed); + } + + { + var time = new DateTimeOffset(2018, 12, 8, 2, 12, 15, TimeSpan.Zero); + Assert.AreEqual(1544235135, time.ToUnixTimeSeconds()); + f.GetStore().Clear(); + f.Value(time); + var bytes = f.GetStoreBytes().ArrayOrCopy(); + var parsed = MsgPackParser.Parse(bytes).GetValue(); + Assert.AreEqual(time, parsed); + } + + { + f.GetStore().Clear(); + Assert.Catch(() => + { + f.Value(new DateTimeOffset()); + }); + } + } + } +} diff --git a/Editor/Tests/MsgPack/TimeTests.cs.meta b/Editor/Tests/MsgPack/TimeTests.cs.meta new file mode 100644 index 000000000..e1ae14b8c --- /dev/null +++ b/Editor/Tests/MsgPack/TimeTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0a025b475357b4d4aa104e839e6791be +timeCreated: 1544154226 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/RPCTests.cs b/Editor/Tests/RPCTests.cs new file mode 100644 index 000000000..32eca3a61 --- /dev/null +++ b/Editor/Tests/RPCTests.cs @@ -0,0 +1,98 @@ +using NUnit.Framework; +using UniJSON.MsgPack; + +namespace UniJSON +{ + public class RPCTests + { + [Test] + public void JsonRpcRequestTest() + { + var f = new JsonFormatter(); + + { + f.Clear(); + var l = JsonParser.Parse("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"num1\",\"params\":[1]}"); + f.Request("num1", 1); + var u = new Utf8String(f.GetStoreBytes()); + var r = JsonParser.Parse(u); + Assert.AreEqual( + l, + r); + } + { + f.Clear(); + f.Request("num2", 2, true); + Assert.AreEqual( + JsonParser.Parse("{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"num2\",\"params\":[2,true]}"), + JsonParser.Parse(new Utf8String(f.GetStoreBytes()))); + } + { + f.Clear(); + f.Request("num3", + 3, true, "abc", false, (string)null, new[] { 1, 2 }); + Assert.AreEqual( + JsonParser.Parse("{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"num3\",\"params\":[3,true,\"abc\",false,null,[1,2]]}"), + JsonParser.Parse(new Utf8String(f.GetStoreBytes()))); + } + } + + [Test] + public void JsonRpcDispatcherTest() + { + var dispatcher = new RpcDispatcher(); + var f = new JsonFormatter(); + + { + f.Clear(); + dispatcher.Register("add", (int a, int b) => a + b); + f.Request("add", 1, 2); + + var parsed = JsonParser.Parse(new Utf8String(f.GetStoreBytes())); + + f.Clear(); + dispatcher.Call(f, parsed["id"].GetInt32(), parsed["method"].GetString(), parsed["params"]); + var response = JsonParser.Parse(new Utf8String(f.GetStoreBytes())); + Assert.AreEqual(3, response["result"].GetInt32()); + } + + { + string msg = null; + dispatcher.Register("print", (string _msg) => { msg = _msg; }); + f.Clear(); + f.Request("print", "hoge"); + + var parsed = JsonParser.Parse(new Utf8String(f.GetStoreBytes())); + f.Clear(); + dispatcher.Call(f, parsed["id"].GetInt32(), parsed["method"].GetString(), parsed["params"]); + + Assert.AreEqual("hoge", msg); + } + } + + [Test] + public void MsgPackRpcDispatcherTest() + { + var dispatcher = new RpcDispatcher(); + var f = new MsgPackFormatter(); + + { + f.GetStore().Clear(); + dispatcher.Register("add", (int a, int b) => a + b); + f.Request("add", 1, 2); + + var request = MsgPackParser.Parse(f.GetStoreBytes()); + Assert.AreEqual(4, request.GetArrayCount()); + Assert.AreEqual(MsgPackFormatter.REQUEST_TYPE, request[0].GetInt32()); + + f.GetStore().Clear(); + dispatcher.Call(f, request[1].GetInt32(), request[2].GetString(), request[3]); + var response = MsgPackParser.Parse(f.GetStoreBytes()); + Assert.AreEqual(4, response.GetArrayCount()); + Assert.AreEqual(MsgPackFormatter.RESPONSE_TYPE, response[0].GetInt32()); + Assert.True(response[2].IsNull()); + Assert.AreEqual(3, response[3].GetInt32()); + } + } + } +} diff --git a/Editor/Tests/RPCTests.cs.meta b/Editor/Tests/RPCTests.cs.meta new file mode 100644 index 000000000..e29355505 --- /dev/null +++ b/Editor/Tests/RPCTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05698e8d4a5f5f64c8482d2d6899301d +timeCreated: 1543250712 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Toml.meta b/Editor/Tests/Toml.meta new file mode 100644 index 000000000..fcfdc8753 --- /dev/null +++ b/Editor/Tests/Toml.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6a719ea2a10120c48959e1fe817301af +folderAsset: yes +timeCreated: 1545735556 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Toml/TomlParserTests.cs b/Editor/Tests/Toml/TomlParserTests.cs new file mode 100644 index 000000000..112a5a723 --- /dev/null +++ b/Editor/Tests/Toml/TomlParserTests.cs @@ -0,0 +1,128 @@ +using NUnit.Framework; + + +/* +namespace UniJSON.Toml +{ + class TomlParserTests + { + [Test] + public void BareKeyTests() + { + { + var result = TomlParser.Parse(@" +value = 1 +"); + Assert.True(result.IsMap()); + Assert.AreEqual(1, result["value"].GetInt32()); + } + } + + [Test] + public void DottedKeyTests() + { + { + var result = TomlParser.Parse(@" +value.value2 = 1 +"); + Assert.True(result.IsMap()); + Assert.AreEqual(1, result["value"]["value2"].GetInt32()); + } + } + + [Test] + public void DuplicatedKey() + { + { + Assert.Catch(() => TomlParser.Parse(@" +value = 1 +value = 2 +")); + } + } + + [Test] + public void QuotedKeyTests() + { + { + var result = TomlParser.Parse(@" +""value"" = 1 +"); + Assert.True(result.IsMap()); + Assert.AreEqual(1, result["value"].GetInt32()); + } + + { + var result = TomlParser.Parse(@" +""[key=value]"" = 1 +"); + Assert.True(result.IsMap()); + Assert.AreEqual(1, result["value"].GetInt32()); + } + } + + [Test] + public void TableTests() + { + { + var result = @" +[table] +value = 1 +".ParseAsToml(); + Assert.True(result.IsMap()); + Assert.AreEqual(1, result["table"]["value"].GetInt32()); + } + + { + var result = @" +[table.table2] +value = 1 +".ParseAsToml(); + Assert.True(result.IsMap()); + Assert.AreEqual(1, result["table"]["table2"]["value"].GetInt32()); + } + } + + [Test] + public void TomlExample() + { + var result = @" +# This is a TOML document. + +title = ""TOML Example"" + +[owner] +name = ""Tom Preston-Werner"" +dob = 1979 - 05 - 27T07: 32:00 - 08:00 # First class dates + +[database] +server = ""192.168.1.1"" +ports = [8001, 8001, 8002] +connection_max = 5000 +enabled = true + +[servers] + +# Indentation (tabs and/or spaces) is allowed but not required + [servers.alpha] + ip = ""10.0.0.1"" + dc = ""eqdc10"" + + [servers.beta] + ip = ""10.0.0.2"" + dc = ""eqdc10"" + +[clients] +data = [ [""gamma"", ""delta""], [1, 2] ] + +# Line breaks are OK when inside arrays +hosts = [ + ""alpha"", + ""omega"" +] +".ParseAsToml(); + Assert.AreEqual("TOML Example", result["title"].GetString()); + } + } +} +*/ diff --git a/Editor/Tests/Toml/TomlParserTests.cs.meta b/Editor/Tests/Toml/TomlParserTests.cs.meta new file mode 100644 index 000000000..b949e4cd5 --- /dev/null +++ b/Editor/Tests/Toml/TomlParserTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7959f4764f02c5e4d9f191e794bc6101 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/TreeTest.cs b/Editor/Tests/TreeTest.cs new file mode 100644 index 000000000..adf69a0fa --- /dev/null +++ b/Editor/Tests/TreeTest.cs @@ -0,0 +1,129 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; + + +namespace GenericTree +{ + /// + /// Generic tree interface + /// + /// + /// + interface ITreeNode + where T : ITreeNode + { + bool IsValid { get; } + int ValueIndex { get; } + U Value { get; } + + bool HasParent { get; } + T Parent { get; } + + IEnumerable Children { get; } + } + + /// + /// Item has parent reference by list index + /// + public interface ITreeItem + { + int ParentIndex { get; } + } + + /// + /// Generic tree implementation + /// + /// + struct TreeNode : ITreeNode, T> + where T : ITreeItem + { + /// + /// Whole tree ndoes + /// + public readonly List Values; + + public bool IsValid + { + get + { + return Values != null; + } + } + + /// + /// This node index + /// + public int ValueIndex + { + get; + private set; + } + + public T Value + { + get + { + if (Values == null) + { + return default(T); + } + return Values[ValueIndex]; + } + } + + public IEnumerable> Children + { + get + { + for (int i = 0; i < Values.Count; ++i) + { + if (Values[i].ParentIndex == ValueIndex) + { + yield return new TreeNode(Values, i); + } + } + } + } + + public bool HasParent + { + get + { + return Value.ParentIndex >= 0 && Value.ParentIndex < Values.Count; + } + } + + public TreeNode Parent + { + get + { + if (Value.ParentIndex < 0) + { + throw new Exception("this may root node"); + } + if (Value.ParentIndex >= Values.Count) + { + throw new IndexOutOfRangeException(); + } + return new TreeNode(Values, Value.ParentIndex); + } + } + + public TreeNode(List values, int index) : this() + { + Values = values; + ValueIndex = index; + } + } + + + class TreeTests + { + [Test] + public void TreeTest() + { + + } + } +} diff --git a/Editor/Tests/TreeTest.cs.meta b/Editor/Tests/TreeTest.cs.meta new file mode 100644 index 000000000..de17c4367 --- /dev/null +++ b/Editor/Tests/TreeTest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 61f513d7f9bea254690ee01fcb70e843 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Utf8StringTest.cs b/Editor/Tests/Utf8StringTest.cs new file mode 100644 index 000000000..50575387d --- /dev/null +++ b/Editor/Tests/Utf8StringTest.cs @@ -0,0 +1,168 @@ +using NUnit.Framework; +using System.Linq; + + +namespace UniJSON +{ + public class Utf8StringTests + { + [Test] + public void Utf8StringTest() + { + var abc = Utf8String.From("abc"); + var ab = Utf8String.From("ab"); + var bc = Utf8String.From("bc"); + + Assert.True(abc.StartsWith(ab)); + Assert.False(ab.StartsWith(abc)); + + Assert.True(abc.EndsWith(bc)); + Assert.False(bc.EndsWith(abc)); + + Assert.AreEqual(Utf8String.From("abbc"), ab.Concat(bc)); + + Assert.AreEqual(2, abc.IndexOf((byte)'c')); + + int pos; + abc.TrySearchAscii((byte)'c', 0, out pos); + Assert.AreEqual(2, pos); + + abc.TrySearchAscii((byte)'c', 1, out pos); + Assert.AreEqual(2, pos); + } + + [Test] + public void ShortUtf8Test() + { + var a0 = Utf8String4.Create("a"); + Assert.AreEqual("a", a0); + var a1 = Utf8String4.Create(new byte[] { (byte)'a', 0x00 }); + Assert.AreEqual(a0, a1); + var a2 = Utf8String4.Create("5"); + Assert.AreEqual(3, a2.ByteLength); + } + + [Test] + public void QuoteTest() + { + { + var value = Utf8String.From("ho5日本語ge"); + var quoted = Utf8String.From("\"ho5日本語ge\""); + Assert.AreEqual(quoted, JsonString.Quote(value)); + Assert.AreEqual(value, JsonString.Unquote(quoted)); + } + + { + var value = Utf8String.From("fuga\n ho5日本語ge"); + var quoted = Utf8String.From("\"fuga\\n ho5日本語ge\""); + Assert.AreEqual(quoted, JsonString.Quote(value)); + Assert.AreEqual(value, JsonString.Unquote(quoted)); + } + } + + [Test] + public void SplitTest() + { + { + var value = Utf8String.From("a/5/c"); + var splited = value.Split((byte)'/').ToArray(); + Assert.AreEqual(3, splited.Length); + Assert.AreEqual(splited[0], Utf8String.From("a")); + Assert.AreEqual(splited[1], Utf8String.From("5")); + Assert.AreEqual(splited[2], Utf8String.From("c")); + } + { + var value = Utf8String.From("/a/5/c/"); + var splited = value.Split((byte)'/').ToArray(); + Assert.AreEqual(4, splited.Length); + Assert.AreEqual(splited[0], Utf8String.From("")); + Assert.AreEqual(splited[1], Utf8String.From("a")); + Assert.AreEqual(splited[2], Utf8String.From("5")); + Assert.AreEqual(splited[3], Utf8String.From("c")); + } + } + + [Test] + public void SplitIntegerTest() + { + Assert.AreEqual("1", Utf8String.From("1 ").SplitInteger().ToString()); + Assert.AreEqual("123", Utf8String.From("123").SplitInteger().ToString()); + Assert.Catch(() => Utf8String.From(" 1").SplitInteger()); + Assert.AreEqual("+12", Utf8String.From("+12\n").SplitInteger().ToString()); + Assert.AreEqual("-123", Utf8String.From("-123\n").SplitInteger().ToString()); + } + + [Test] + public void AtoiTest() + { + Assert.AreEqual(1234, Utf8String.From("1234").ToInt32()); + } + + [Test] + public void ToCharTest() + { + { + // 1byte + var c = 'A'; + Assert.AreEqual(1, Utf8String.From(c.ToString()).GetFirst().CurrentByteLength); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Unicode); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Char); + } + { + // 2byte + var c = '¢'; + Assert.AreEqual(2, Utf8String.From(c.ToString()).GetFirst().CurrentByteLength); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Unicode); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Char); + } + { + // 3byte + var c = '5'; + Assert.AreEqual(3, Utf8String.From(c.ToString()).GetFirst().CurrentByteLength); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Unicode); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Char); + } + { + var c = '仡'; + Assert.AreEqual(3, Utf8String.From(c.ToString()).GetFirst().CurrentByteLength); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Unicode); + Assert.AreEqual(c, Utf8String.From(c.ToString()).GetFirst().Char); + } + { + // emoji + var s = "😃"; + Assert.AreEqual(4, Utf8String.From(s).GetFirst().CurrentByteLength); + Assert.AreEqual(0x1F603, Utf8String.From(s).GetFirst().Unicode); + Assert.Catch(() => + { + var a = Utf8String.From(s).GetFirst().Char; + }); + } + } + + [Test] + public void FromStringTest() + { + var buffer = new byte[12]; + + { + var src = "abc"; + var utf8 = Utf8String.From(src, buffer); + Assert.AreEqual(3, utf8.ByteLength); + Assert.AreEqual(src, utf8.ToString()); + } + { + var src = "¢"; + var utf8 = Utf8String.From(src, buffer); + Assert.AreEqual(2, utf8.ByteLength); + Assert.AreEqual(src, utf8.ToString()); + } + { + var src = "5"; + var utf8 = Utf8String.From(src, buffer); + Assert.AreEqual(3, utf8.ByteLength); + Assert.AreEqual(src, utf8.ToString()); + } + } + } +} diff --git a/Editor/Tests/Utf8StringTest.cs.meta b/Editor/Tests/Utf8StringTest.cs.meta new file mode 100644 index 000000000..d445b4817 --- /dev/null +++ b/Editor/Tests/Utf8StringTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c8821be74ee9054d81e25151e023015 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..3299d454f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 ousttrue + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 000000000..0f8b70179 --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0cd28905c8909143a42de7256c727e7 +timeCreated: 1526055773 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Profiling.meta b/Profiling.meta new file mode 100644 index 000000000..c31abb903 --- /dev/null +++ b/Profiling.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 92f8492893093234995cd80054d69cdd +folderAsset: yes +timeCreated: 1535530113 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Profiling/.gitignore b/Profiling/.gitignore new file mode 100644 index 000000000..2f96ad8ed --- /dev/null +++ b/Profiling/.gitignore @@ -0,0 +1,15 @@ +/.vs +/bin +/bin.meta +/obj +/obj.meta +*.csproj.user +*.csproj.user.meta +*.psess +*.psess.meta +*.vsp +*.vsp.meta +*.vspx +*.vspx.meta +App.config.meta + diff --git a/Profiling/App.config b/Profiling/App.config new file mode 100644 index 000000000..00bfd114a --- /dev/null +++ b/Profiling/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Profiling/Program.cs b/Profiling/Program.cs new file mode 100644 index 000000000..04241891b --- /dev/null +++ b/Profiling/Program.cs @@ -0,0 +1,16 @@ +using System.IO; +using System.Text; + +#if UNIJSON_PROFILING +namespace UniJSONPRofiling +{ + class Program + { + static void Main(string[] args) + { + var json = File.ReadAllText(args[0], Encoding.UTF8); + var parsed = UniJSON.JsonParser.Parse(json); + } + } +} +#endif \ No newline at end of file diff --git a/Profiling/Program.cs.meta b/Profiling/Program.cs.meta new file mode 100644 index 000000000..a309fb35a --- /dev/null +++ b/Profiling/Program.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a9e570967f10a8b4bb492b9dde8366a9 +timeCreated: 1533801169 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Profiling/Properties.meta b/Profiling/Properties.meta new file mode 100644 index 000000000..037ecf939 --- /dev/null +++ b/Profiling/Properties.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 281449d948b75bf438f20f57379e18fb +folderAsset: yes +timeCreated: 1533801167 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Profiling/Properties/AssemblyInfo.cs b/Profiling/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..23106c047 --- /dev/null +++ b/Profiling/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 +// アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更してください。 +[assembly: AssemblyTitle("UniJSONPRofiling")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UniJSONPRofiling")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから +// 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 +// その型の ComVisible 属性を true に設定してください。 +[assembly: ComVisible(false)] + +// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります +[assembly: Guid("59cc2d5e-d4c5-4118-b6db-d6a9d9ba01f1")] + +// アセンブリのバージョン情報は次の 4 つの値で構成されています: +// +// メジャー バージョン +// マイナー バージョン +// ビルド番号 +// Revision +// +// すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます +// 既定値にすることができます: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Profiling/Properties/AssemblyInfo.cs.meta b/Profiling/Properties/AssemblyInfo.cs.meta new file mode 100644 index 000000000..1f9f0a132 --- /dev/null +++ b/Profiling/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 08ef0de807abd6a47b854bd0e546d64e +timeCreated: 1533801169 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Profiling/UniJSONPRofiling.csproj b/Profiling/UniJSONPRofiling.csproj new file mode 100644 index 000000000..209205526 --- /dev/null +++ b/Profiling/UniJSONPRofiling.csproj @@ -0,0 +1,80 @@ + + + + + Debug + AnyCPU + {59CC2D5E-D4C5-4118-B6DB-D6A9D9BA01F1} + Exe + UniJSONPRofiling + UniJSONPRofiling + v4.6.1 + 512 + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG;UNIJSON_PROFILING + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4.6.1 %28x86 および x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + diff --git a/Profiling/UniJSONPRofiling.csproj.meta b/Profiling/UniJSONPRofiling.csproj.meta new file mode 100644 index 000000000..41854a922 --- /dev/null +++ b/Profiling/UniJSONPRofiling.csproj.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 442d08a1c2a1c1045a9e56364fefbc22 +timeCreated: 1533801167 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Profiling/UniJSONPRofiling.sln b/Profiling/UniJSONPRofiling.sln new file mode 100644 index 000000000..a4e253a0b --- /dev/null +++ b/Profiling/UniJSONPRofiling.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2042 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniJSONPRofiling", "UniJSONPRofiling.csproj", "{59CC2D5E-D4C5-4118-B6DB-D6A9D9BA01F1}" +EndProject +Global + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {59CC2D5E-D4C5-4118-B6DB-D6A9D9BA01F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59CC2D5E-D4C5-4118-B6DB-D6A9D9BA01F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59CC2D5E-D4C5-4118-B6DB-D6A9D9BA01F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59CC2D5E-D4C5-4118-B6DB-D6A9D9BA01F1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9524149F-AB76-43F8-8F93-D198D87C95C5} + EndGlobalSection +EndGlobal diff --git a/Profiling/UniJSONPRofiling.sln.meta b/Profiling/UniJSONPRofiling.sln.meta new file mode 100644 index 000000000..93e7fad58 --- /dev/null +++ b/Profiling/UniJSONPRofiling.sln.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 920f66a990de731479c5bc11d2a3b420 +timeCreated: 1533801168 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md new file mode 100644 index 000000000..82a5a0221 --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +# UniJSON +JSON serializer and deserializer and schema utilities for Unity(.Net3.5) + +## Usage + +### JSON Create + +```cs +var f = new JsonFormatter(); +f.BeginMap(); +f.Key("X"); f.Value(1); +f.Key("Y"); f.Value(1); +f.Key("Z"); f.Value(1); +f.EndMap(); +var json = f.ToString(); +// {"X":1,"Y":2,"Z":3} +``` + +### JSON Serialize + +Serialize public fields automatically. + +```cs +var f = new JsonFormatter(); +f.Serialize(new Vector3(1, 2, 3)); +var json = f.ToString(); +// {"X":1,"Y":2,"Z":3} +``` + +### JSON Parse + +```cs +var json = "{\"X\":1,\"Y\":2,\"Z\":3}"; +var parsed = json.ParseAsJson(); +var x = parsed["X"].GetInt32(); +``` + +### JSON Deserialize + +```cs +var v = default(Vector3); +json.Deserialize(ref v); +``` + +### JSON Schema + +```cs +[Serializable] +public class glTFSparseIndices +{ + [JsonSchema(Minimum = 0)] + public int bufferView; + + [JsonSchema(Minimum = 0)] + public int byteOffset; + + [JsonSchema(EnumSerializationType = EnumSerializationType.AsInt)] + public glComponentType componentType; + + // empty schemas + public object extensions; + public object extras; +} + + +[Test] +public void AccessorSparseIndices() +{ + // from JSON schema + var path = Path.GetFullPath(Application.dataPath + "/../glTF/specification/2.0/schema"); + var SchemaDir = new FileSystemAccessor(path); + var fromSchema = JsonSchema.ParseFromPath(SchemaDir.Get("accessor.sparse.indices.schema.json")); + + // from C# type definition + var fromClass = JsonSchema.FromType(); + + Assert.AreEqual(fromSchema, fromClass); +} +``` + +### MsgPack + +Same as json interface + +```cs +var f = new MsgPackFormatter(); +f.Serialize(new Vector3(1, 2, 3)); +ArraySegment msgpack = f.GetStoreBytes(); + +var parsed = msgpack.ParseAsMsgPack(); +var x = parsed["X"].GetInt32(); +``` + +### TOML + +WIP + +```cs +var toml =@" +X = 1 +Y = 2 +Z = 3 +"; +var parsed = toml.ParseAsToml(); +var x = parsed["X"].GetInt32(); +``` + +## Reference +### JSON + +* https://www.json.org/ + +### JSON Schema + +* http://json-schema.org/ +* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0/schema + +### JSON Patch + +* http://jsonpatch.com/ + +### JSON RPC + +* https://www.jsonrpc.org/specification + + +### MsgPack + +* https://github.com/msgpack/msgpack/blob/master/spec.md + +### MsgPack-RPC + +* https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + +### TOML + +* https://github.com/toml-lang/toml + diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 000000000..ccadb4f3f --- /dev/null +++ b/README.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aacd90cc96ffbef4bb472bcb90b2620d +timeCreated: 1526055773 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts.meta b/Scripts.meta new file mode 100644 index 000000000..55a5d2226 --- /dev/null +++ b/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 817581cb4547fa04e877a77b4888dcc8 +folderAsset: yes +timeCreated: 1526055856 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ActionDisposer.cs b/Scripts/ActionDisposer.cs new file mode 100644 index 000000000..ca0be2b1f --- /dev/null +++ b/Scripts/ActionDisposer.cs @@ -0,0 +1,20 @@ +using System; + + +namespace UniJSON +{ + public struct ActionDisposer : IDisposable + { + Action m_action; + + public ActionDisposer(Action action) + { + m_action = action; + } + + public void Dispose() + { + m_action(); + } + } +} diff --git a/Scripts/ActionDisposer.cs.meta b/Scripts/ActionDisposer.cs.meta new file mode 100644 index 000000000..1a21d6618 --- /dev/null +++ b/Scripts/ActionDisposer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ff15446e31b14ac409251c931b7c2038 +timeCreated: 1531893103 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ByteBuffer.cs b/Scripts/ByteBuffer.cs new file mode 100644 index 000000000..be827ee9f --- /dev/null +++ b/Scripts/ByteBuffer.cs @@ -0,0 +1,90 @@ +using System; + + +namespace UniJSON +{ + public class ByteBuffer + { + Byte[] m_buffer; + public ArraySegment Bytes + { + get { return new ArraySegment(m_buffer, 0, Count); } + } + + public ByteBuffer() + { + + } + + public ByteBuffer(Byte[] buffer) + { + m_buffer = buffer; + } + + int m_used; + public int Count + { + get { return m_used; } + } + + public int Remain + { + get { + if (m_buffer == null) return 0; + return m_buffer.Length - m_used; + } + } + + void Ensure(int size) + { + if (m_buffer != null && size < m_buffer.Length - m_used) + { + return; + } + var buffer = new Byte[m_used + size]; + if (m_buffer != null && m_used > 0) + { + Buffer.BlockCopy(m_buffer, 0, buffer, 0, m_used); + } + m_buffer = buffer; + } + + public void Push(Byte b) + { + Ensure(1); + m_buffer[m_used++] = b; + } + + public void Push(Byte[] buffer) + { + Push(new ArraySegment(buffer)); + } + + public void Push(ArraySegment buffer) + { + Ensure(buffer.Count); + Buffer.BlockCopy(buffer.Array, buffer.Offset, m_buffer, m_used, buffer.Count); + m_used += buffer.Count; + } + + public void Unshift(int size) + { + if (size > m_used) + { + throw new ArgumentException(); + } + + if (m_used - size < size) + { + Buffer.BlockCopy(m_buffer, m_used, m_buffer, 0, m_used - size); + m_used = m_used - size; + } + else + { + var buffer = new Byte[m_used]; + Buffer.BlockCopy(m_buffer, size, buffer, 0, m_used - size); + m_buffer = buffer; + } + } + } +} diff --git a/Scripts/ByteBuffer.cs.meta b/Scripts/ByteBuffer.cs.meta new file mode 100644 index 000000000..6807b17bc --- /dev/null +++ b/Scripts/ByteBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5de1b9c915ceb8d41b95bdc432680fc3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Exceptions.cs b/Scripts/Exceptions.cs new file mode 100644 index 000000000..d77e0a281 --- /dev/null +++ b/Scripts/Exceptions.cs @@ -0,0 +1,34 @@ +using System; + + +namespace UniJSON +{ + public class TreeValueException : ArgumentException + { + protected TreeValueException(string msg) : base(msg) { } + } + + /// + ///Exception failure + /// + public class ParserException : TreeValueException + { + public ParserException(string msg) : base(msg) { } + } + + /// + /// Successfully parsed, but fail to getValue + /// + public class DeserializationException : TreeValueException + { + public DeserializationException(string msg) : base(msg) { } + } + + /// + /// Formatter exception. key value violation + /// + public class FormatterException : TreeValueException + { + public FormatterException(string msg) : base(msg) { } + } +} diff --git a/Scripts/Exceptions.cs.meta b/Scripts/Exceptions.cs.meta new file mode 100644 index 000000000..20620ad03 --- /dev/null +++ b/Scripts/Exceptions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d854b575d2e031f40b37a49e1bff8656 +timeCreated: 1545735558 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions.meta b/Scripts/Extensions.meta new file mode 100644 index 000000000..c0f932bd0 --- /dev/null +++ b/Scripts/Extensions.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 64b77fe68ca869c40b77ae2f19862579 +folderAsset: yes +timeCreated: 1526057063 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions/ArraySegmentExtensions.cs b/Scripts/Extensions/ArraySegmentExtensions.cs new file mode 100644 index 000000000..7f72c809f --- /dev/null +++ b/Scripts/Extensions/ArraySegmentExtensions.cs @@ -0,0 +1,85 @@ +using System; +using System.Linq; +using System.Collections.Generic; + + +namespace UniJSON +{ + public static class ArraySegmentExtensions + { + public static T[] ArrayOrCopy(this ArraySegment self) + { + if (self.Array == null || self.Count==0) + { + return new T[] { }; + } + else if(self.Offset==0 && self.Count==self.Array.Length) + { + return self.Array; + } + else + { + var array = new T[self.Count]; + Array.Copy(self.Array, self.Offset, array, 0, self.Count); + return array; + } + } + + public static IEnumerable ToEnumerable(this ArraySegment self) + { + return self.Array.Skip(self.Offset).Take(self.Count); + } + + public static void Set(this ArraySegment self, int index, T value) + { + if (index < 0 || index >= self.Count) + { + throw new ArgumentOutOfRangeException(); + } + self.Array[self.Offset + index] = value; + } + + public static T Get(this ArraySegment self, int index) + { + if (index < 0 || index >= self.Count) + { + throw new ArgumentOutOfRangeException(); + } + return self.Array[self.Offset + index]; + } + + public static ArraySegment Advance(this ArraySegment self, Int32 n) + { + return new ArraySegment(self.Array, self.Offset + n, self.Count - n); + } + + public static ArraySegment Take(this ArraySegment self, Int32 n) + { + return new ArraySegment(self.Array, self.Offset, n); + } + + public static T[] TakeReversedArray(this ArraySegment self, Int32 n) + { + var array = new T[n]; + var x = n - 1; + for (int i = 0; i < n; ++i, --x) + { + array[i] = self.Get(x); + } + return array; + } + + public static byte[] Concat(this byte[] lhs, ArraySegment rhs) + { + return new ArraySegment(lhs).Concat(rhs); + } + + public static byte[] Concat(this ArraySegment lhs, ArraySegment rhs) + { + var bytes = new byte[lhs.Count + rhs.Count]; + Buffer.BlockCopy(lhs.Array, lhs.Offset, bytes, 0, lhs.Count); + Buffer.BlockCopy(rhs.Array, rhs.Offset, bytes, lhs.Count, rhs.Count); + return bytes; + } + } +} diff --git a/Scripts/Extensions/ArraySegmentExtensions.cs.meta b/Scripts/Extensions/ArraySegmentExtensions.cs.meta new file mode 100644 index 000000000..d6c810e4c --- /dev/null +++ b/Scripts/Extensions/ArraySegmentExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 12d3e22e2e62d4948a5aff4bc42208e9 +timeCreated: 1495517072 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions/ByteExtensions.cs b/Scripts/Extensions/ByteExtensions.cs new file mode 100644 index 000000000..cae4def96 --- /dev/null +++ b/Scripts/Extensions/ByteExtensions.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; + +namespace UniJSON +{ + public static class ByteExtensions + { + public static Byte GetHexDigit(this UInt16 n, int index) + { + return (Byte)(n >> 8 * index & 0xff); + } + public static Byte GetHexDigit(this UInt32 n, int index) + { + return (Byte)(n >> 8 * index & 0xff); + } + public static Byte GetHexDigit(this UInt64 n, int index) + { + return (Byte)(n >> 8 * index & 0xff); + } + public static Byte GetHexDigit(this Int16 n, int index) + { + return (Byte)(n >> 8 * index & 0xff); + } + public static Byte GetHexDigit(this Int32 n, int index) + { + return (Byte)(n >> 8 * index & 0xff); + } + public static Byte GetHexDigit(this Int64 n, int index) + { + return (Byte)(n >> 8 * index & 0xff); + } + + public static UInt32 ToUint32(this Single n, Byte[] buffer) + { + if (buffer.Length < 4) + { + throw new ArgumentException(); + } + using (var ms = new MemoryStream(buffer)) + using (var w = new BinaryWriter(ms)) + { + w.Write(n); + } + return BitConverter.ToUInt32(buffer, 0); + } + public static UInt64 ToUint64(this Double n, Byte[] buffer) + { + if (buffer.Length < 8) + { + throw new ArgumentException(); + } + using (var ms = new MemoryStream(buffer)) + using (var w = new BinaryWriter(ms)) + { + w.Write(n); + } + return BitConverter.ToUInt64(buffer, 0); + } + } +} diff --git a/Scripts/Extensions/ByteExtensions.cs.meta b/Scripts/Extensions/ByteExtensions.cs.meta new file mode 100644 index 000000000..cb3e4ccf9 --- /dev/null +++ b/Scripts/Extensions/ByteExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: aa32ad3ea4c1ec540a03225c0d520af9 +timeCreated: 1495517078 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions/DateTimeOffsetExtensions.cs b/Scripts/Extensions/DateTimeOffsetExtensions.cs new file mode 100644 index 000000000..3455b72fe --- /dev/null +++ b/Scripts/Extensions/DateTimeOffsetExtensions.cs @@ -0,0 +1,21 @@ +using System; + + +namespace UniJSON +{ + public static class DateTimeOffsetExtensions + { + public const long TicksPerSecond = 10000000; + public readonly static DateTimeOffset EpocTime = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero); +#if !NET_4_6 && !NET_STANDARD_2_0 + public static long ToUnixTimeSeconds(this DateTimeOffset now) + { + if (now < EpocTime) + { + throw new ArgumentOutOfRangeException(); + } + return (now - EpocTime).Ticks / TicksPerSecond; + } +#endif + } +} diff --git a/Scripts/Extensions/DateTimeOffsetExtensions.cs.meta b/Scripts/Extensions/DateTimeOffsetExtensions.cs.meta new file mode 100644 index 000000000..9aca14333 --- /dev/null +++ b/Scripts/Extensions/DateTimeOffsetExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d2fd687914fcde848ab36867817cb873 +timeCreated: 1544155597 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions/EnumExtensions.cs b/Scripts/Extensions/EnumExtensions.cs new file mode 100644 index 000000000..f1b26ddfe --- /dev/null +++ b/Scripts/Extensions/EnumExtensions.cs @@ -0,0 +1,15 @@ +using System; + + +namespace UniJSON +{ + public static class EnumExtensions + { + public static bool HasFlag(this Enum keys, Enum flag) + { + if (keys.GetType() != flag.GetType()) + throw new ArgumentException("Type Mismatch"); + return (Convert.ToUInt64(keys) & Convert.ToUInt64(flag)) != 0; + } + } +} diff --git a/Scripts/Extensions/EnumExtensions.cs.meta b/Scripts/Extensions/EnumExtensions.cs.meta new file mode 100644 index 000000000..c10223d19 --- /dev/null +++ b/Scripts/Extensions/EnumExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d8691eccccb3e214db8bc5b86179f428 +timeCreated: 1526057070 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions/ParserExtensions.cs b/Scripts/Extensions/ParserExtensions.cs new file mode 100644 index 000000000..5adaf3b86 --- /dev/null +++ b/Scripts/Extensions/ParserExtensions.cs @@ -0,0 +1,52 @@ +using System; + + +namespace UniJSON +{ + public static class StringExtensions + { + public static ListTreeNode ParseAsJson(this string json) + { + return JsonParser.Parse(json); + } + public static ListTreeNode ParseAsJson(this Utf8String json) + { + return JsonParser.Parse(json); + } + public static ListTreeNode ParseAsJson(this byte[] bytes) + { + return JsonParser.Parse(new Utf8String(bytes)); + } + public static ListTreeNode ParseAsJson(this ArraySegment bytes) + { + return JsonParser.Parse(new Utf8String(bytes)); + } + + public static ListTreeNode ParseAsMsgPack(this byte[] bytes) + { + return MsgPackParser.Parse(bytes); + } + public static ListTreeNode ParseAsMsgPack(this ArraySegment bytes) + { + return MsgPackParser.Parse(bytes); + } + + public static ListTreeNode ParseAsToml(this string toml) + { + return TomlParser.Parse(toml); + } + public static ListTreeNode ParseAsToml(this Utf8String toml) + { + return TomlParser.Parse(toml); + } + public static ListTreeNode ParseAsToml(this byte[] bytes) + { + return TomlParser.Parse(new Utf8String(bytes)); + } + public static ListTreeNode ParseAsToml(this ArraySegment bytes) + { + return TomlParser.Parse(new Utf8String(bytes)); + } + + } +} diff --git a/Scripts/Extensions/ParserExtensions.cs.meta b/Scripts/Extensions/ParserExtensions.cs.meta new file mode 100644 index 000000000..18343d27a --- /dev/null +++ b/Scripts/Extensions/ParserExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c25e655e5dc993145a70d9ddde6a6034 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Extensions/TypeExtensions.cs b/Scripts/Extensions/TypeExtensions.cs new file mode 100644 index 000000000..56bce32a3 --- /dev/null +++ b/Scripts/Extensions/TypeExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; +using System.Collections.Generic; + + +namespace UniJSON +{ + public static class TypeExtensions + { + public static bool GetIsGenericList(this Type t) + { + if (t == null) return false; + + return t.IsGenericType + && (t.GetGenericTypeDefinition() == typeof(List<>)); + } + + public static bool GetIsGenericDictionary(this Type t) + { + if (t == null) return false; + + return t.IsGenericType + && (t.GetGenericTypeDefinition() == typeof(Dictionary<,>) + && t.GetGenericArguments().FirstOrDefault() == typeof(string) + ); + } + } +} diff --git a/Scripts/Extensions/TypeExtensions.cs.meta b/Scripts/Extensions/TypeExtensions.cs.meta new file mode 100644 index 000000000..d52282775 --- /dev/null +++ b/Scripts/Extensions/TypeExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2fb728ca27f90c947890313df5f94d4d +timeCreated: 1531634657 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/FormatterExtensions.cs b/Scripts/FormatterExtensions.cs new file mode 100644 index 000000000..849e7d830 --- /dev/null +++ b/Scripts/FormatterExtensions.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Linq; +using System.Reflection; + + +namespace UniJSON +{ + public static partial class FormatterExtensions + { + public static void Clear(this IFormatter f) + { + f.GetStore().Clear(); + } + + public static ArraySegment GetStoreBytes(this IFormatter f) + { + return f.GetStore().Bytes; + } + + public static void Key(this IFormatter f, string x) + { + f.Key(Utf8String.From(x)); + } + + public static void Value(this IFormatter f, IEnumerable raw, int count) + { + f.Value(new ArraySegment(raw.Take(count).ToArray())); + } + + public static void Value(this IFormatter f, Byte[] bytes) + { + f.Value(new ArraySegment(bytes)); + } + + public static void Value(this IFormatter f, UnityEngine.Vector3 v) + { + //CommaCheck(); + f.BeginMap(3); + f.Key("x"); f.Value(v.x); + f.Key("y"); f.Value(v.y); + f.Key("z"); f.Value(v.z); + f.EndMap(); + } + + static MethodInfo GetMethod(Expression> expression) + { + var method = typeof(FormatterExtensions).GetMethod("Serialize"); + return method.MakeGenericMethod(typeof(T)); + } + + public static void KeyValue(this IFormatter f, Expression> expression) + { + var func = expression.Compile(); + var value = func(); + if (value != null) + { + var body = expression.Body as MemberExpression; + if (body == null) + { + body = ((UnaryExpression)expression.Body).Operand as MemberExpression; + } + f.Key(body.Member.Name); + f.Serialize(expression.Compile()()); + //var method = GetMethod(expression); + //method.Invoke(this, new object[] { value }); + } + } + } +} diff --git a/Scripts/FormatterExtensions.cs.meta b/Scripts/FormatterExtensions.cs.meta new file mode 100644 index 000000000..86e650ac9 --- /dev/null +++ b/Scripts/FormatterExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eb87cc122742d7544b818c171b15f746 +timeCreated: 1540812583 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/FormatterExtensionsSerializer.cs b/Scripts/FormatterExtensionsSerializer.cs new file mode 100644 index 000000000..eaf717ca7 --- /dev/null +++ b/Scripts/FormatterExtensionsSerializer.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace UniJSON +{ + public static class FormatterExtensionsSerializer + { + public static void SerializeDictionary(this IFormatter f, IDictionary dictionary) + { + f.BeginMap(dictionary.Count); + foreach (var kv in dictionary) + { + f.Key(kv.Key); + f.SerializeObject(kv.Value); + } + f.EndMap(); + } + + public static void SerializeArray(this IFormatter f, IEnumerable values) + { + f.BeginList(values.Count()); + foreach (var value in values) + { + f.Serialize(value); + } + f.EndList(); + } + + public static void SerializeObjectArray(this IFormatter f, object[] array) + { + f.BeginList(array.Length); + foreach (var x in array) + { + f.SerializeObject(x); + } + f.EndList(); + } + + public static void SerializeObject(this IFormatter f, object value) + { + if (value == null) + { + f.Null(); + } + else + { + typeof(FormatterExtensionsSerializer).GetMethod("Serialize").MakeGenericMethod(value.GetType()).Invoke(null, new object[] { f, value }); + } + } + + public static void Serialize(this IFormatter f, T arg) + { + if (arg == null) + { + f.Null(); + return; + } + + GenericSerializer.Serialize(f, arg); + } + + public static void SetCustomSerializer(Action serializer) + { + GenericSerializer.Set(serializer); + } + } + + static class GenericSerializer + { + delegate void Serializer(IFormatter f, T t); + + static Action GetSerializer(Type t) + { + // object + if (typeof(T) == typeof(object) && t.GetType() != typeof(object)) + { + var self = Expression.Parameter(typeof(IFormatter), "f"); + var arg = Expression.Parameter(t, "value"); + var call = Expression.Call(typeof(FormatterExtensionsSerializer), "SerializeObject", + new Type[] { }, + self, arg); + var lambda = Expression.Lambda(call, self, arg); + return (Action)lambda.Compile(); + } + + try + { + // primitive + var mi = typeof(IFormatter).GetMethod("Value", new Type[] { t }); + if (mi != null) + { + // premitives + var self = Expression.Parameter(typeof(IFormatter), "f"); + var arg = Expression.Parameter(t, "value"); + var call = Expression.Call(self, mi, arg); + + var lambda = Expression.Lambda(call, self, arg); + return (Action)lambda.Compile(); + } + } + catch (AmbiguousMatchException) + { + // do nothing + } + + { + // dictionary + var idictionary = t.GetInterfaces().FirstOrDefault(x => + x.IsGenericType + && x.GetGenericTypeDefinition() == typeof(IDictionary<,>) + && x.GetGenericArguments()[0] == typeof(string) + ); + if (idictionary != null) + { + //var mi = typeof(IFormatter).GetMethod("SerializeDictionary", new Type[] { t }); + var self = Expression.Parameter(typeof(IFormatter), "f"); + var arg = Expression.Parameter(t, "value"); + var call = Expression.Call(typeof(FormatterExtensionsSerializer), "SerializeDictionary", + new Type[] { }, + self, arg); + var lambda = Expression.Lambda(call, self, arg); + return (Action)lambda.Compile(); + } + } + + { + // object[] + if (t == typeof(object[])) + { + var self = Expression.Parameter(typeof(IFormatter), "f"); + var arg = Expression.Parameter(t, "value"); + var call = Expression.Call(typeof(FormatterExtensionsSerializer), "SerializeObjectArray", + new Type[] { }, + self, arg); + var lambda = Expression.Lambda(call, self, arg); + return (Action)lambda.Compile(); + } + } + + { + // list + var ienumerable = t.GetInterfaces().FirstOrDefault(x => + x.IsGenericType + && x.GetGenericTypeDefinition() == typeof(IEnumerable<>) + ); + if (ienumerable != null) + { + var self = Expression.Parameter(typeof(IFormatter), "f"); + var arg = Expression.Parameter(t, "value"); + var call = Expression.Call(typeof(FormatterExtensionsSerializer), "SerializeArray", + ienumerable.GetGenericArguments(), + self, arg); + var lambda = Expression.Lambda(call, self, arg); + return (Action)lambda.Compile(); + } + } + + { + // reflection + var schema = JsonSchema.FromType(); + return (IFormatter f, T value) => schema.Serialize(f, value); + } + + //throw new NotImplementedException(); + } + + static Serializer s_serializer; + + public static void Set(Action serializer) + { + s_serializer = new Serializer(serializer); + } + + public static void Serialize(IFormatter f, T t) + { + if (s_serializer == null) + { + s_serializer = new Serializer(GetSerializer(typeof(T))); + } + s_serializer(f, t); + } + } +} diff --git a/Scripts/FormatterExtensionsSerializer.cs.meta b/Scripts/FormatterExtensionsSerializer.cs.meta new file mode 100644 index 000000000..a0422f7e8 --- /dev/null +++ b/Scripts/FormatterExtensionsSerializer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 11342b30ed6802d4ebccbcf85663c6a0 +timeCreated: 1543520703 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/GenericCast.cs b/Scripts/GenericCast.cs new file mode 100644 index 000000000..9b37f9375 --- /dev/null +++ b/Scripts/GenericCast.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq.Expressions; + + +namespace UniJSON +{ + struct GenericCast + { + public static T Null() + { + if (typeof(T).IsClass) + { + return default(T); + } + else + { + throw new MsgPackTypeException("can not null"); + } + } + + delegate T CastFunc(S value); + static CastFunc s_cast; + + delegate Func ConstFuncCreator(S value); + static ConstFuncCreator s_const; + + public static Func Const(S value) + { + if (s_const == null) + { + s_const = new ConstFuncCreator(GenericCast.CreateConst()); + } + return s_const(value); + } + + public static T Cast(S value) + { + if (s_cast == null) + { + s_cast = new CastFunc(GenericCast.CreateCast()); + } + return s_cast(value); + } + } + + static class GenericCast + { + public static Func CreateCast() + { + if (typeof(S) == typeof(T)) + { + // through + var src = Expression.Parameter(typeof(S), "src"); + var lambda = Expression.Lambda(src, src); + return (Func)lambda.Compile(); + } + else + { + // cast + var src = Expression.Parameter(typeof(S), "src"); + var cast = Expression.Convert(src, typeof(T)); + var lambda = Expression.Lambda(cast, src); + return (Func)lambda.Compile(); + } + } + + public static Func> CreateConst() + { + var src = Expression.Parameter(typeof(S), "src"); + var convert = Expression.Convert(src, typeof(T)); + var lambda = (Func)Expression.Lambda(convert, src).Compile(); + return s => + { + var t = lambda(s); + return () => t; + }; + } + } +} diff --git a/Scripts/GenericCast.cs.meta b/Scripts/GenericCast.cs.meta new file mode 100644 index 000000000..d653d7ef2 --- /dev/null +++ b/Scripts/GenericCast.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5e1cb5b0419b4a04da69e90f4890c349 +timeCreated: 1545134074 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IFileSystemAccessor.cs b/Scripts/IFileSystemAccessor.cs new file mode 100644 index 000000000..cf4aa8546 --- /dev/null +++ b/Scripts/IFileSystemAccessor.cs @@ -0,0 +1,53 @@ +using System.IO; +using System.Text; + + +namespace UniJSON +{ + public interface IFileSystemAccessor + { + string ReadAllText(); + string ReadAllText(string relativePath); + IFileSystemAccessor Get(string relativePath); + } + + public class FileSystemAccessor : IFileSystemAccessor + { + string m_path; + string m_baseDir; + public FileSystemAccessor(string path) + { + m_path = path; + if (Directory.Exists(path)) + { + m_baseDir = path; + } + else + { + m_baseDir = Path.GetDirectoryName(path); + } + } + + public override string ToString() + { + return "<" + Path.GetFileName(m_path) + ">"; + } + + public string ReadAllText() + { + return File.ReadAllText(m_path, Encoding.UTF8); + } + + public string ReadAllText(string relativePath) + { + var path = Path.Combine(m_baseDir, relativePath); + return File.ReadAllText(path, Encoding.UTF8); + } + + public IFileSystemAccessor Get(string relativePath) + { + var path = Path.Combine(m_baseDir, relativePath); + return new FileSystemAccessor(path); + } + } +} diff --git a/Scripts/IFileSystemAccessor.cs.meta b/Scripts/IFileSystemAccessor.cs.meta new file mode 100644 index 000000000..823c7de74 --- /dev/null +++ b/Scripts/IFileSystemAccessor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 865a0727ffe095a40abbb2b8d799e720 +timeCreated: 1531504314 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IFormatter.cs b/Scripts/IFormatter.cs new file mode 100644 index 000000000..3fe99953e --- /dev/null +++ b/Scripts/IFormatter.cs @@ -0,0 +1,42 @@ +using System; + + +namespace UniJSON +{ + public interface IFormatter + { + IStore GetStore(); + + void BeginList(int n); + void EndList(); + + void BeginMap(int n); + void EndMap(); + + void Key(Utf8String x); + + void Null(); + + void Value(Utf8String x); + void Value(String x); + + void Value(ArraySegment bytes); + + void Value(Boolean x); + + void Value(Byte x); + void Value(UInt16 x); + void Value(UInt32 x); + void Value(UInt64 x); + + void Value(SByte x); + void Value(Int16 x); + void Value(Int32 x); + void Value(Int64 x); + + void Value(Single x); + void Value(Double x); + + void Value(DateTimeOffset x); + } +} diff --git a/Scripts/IFormatter.cs.meta b/Scripts/IFormatter.cs.meta new file mode 100644 index 000000000..48c1d76e6 --- /dev/null +++ b/Scripts/IFormatter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5fb858fc98e29c54d87df97ead98608e +timeCreated: 1540812551 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IStore.meta b/Scripts/IStore.meta new file mode 100644 index 000000000..7cb52dbd8 --- /dev/null +++ b/Scripts/IStore.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2596156c052e9eb4d888f01f13445446 +folderAsset: yes +timeCreated: 1531806172 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IStore/ByteUnion.cs b/Scripts/IStore/ByteUnion.cs new file mode 100644 index 000000000..ff5389ba6 --- /dev/null +++ b/Scripts/IStore/ByteUnion.cs @@ -0,0 +1,109 @@ +using System; +using System.Net; +using System.Runtime.InteropServices; + + +namespace UniJSON +{ + public static class ByteUnion + { + [StructLayout(LayoutKind.Explicit)] + public struct WordValue + { + [FieldOffset(0)] + public Int16 Signed; + [FieldOffset(0)] + public UInt16 Unsigned; + + [FieldOffset(0)] + public byte Byte0; + [FieldOffset(1)] + public byte Byte1; + + public WordValue HostToNetworkOrder() { return new WordValue { Signed = IPAddress.HostToNetworkOrder(Signed) }; } + + public static WordValue Create(Int16 value) { return new WordValue { Signed = value }; } + public static WordValue Create(UInt16 value) { return new WordValue { Unsigned = value }; } + } + + [StructLayout(LayoutKind.Explicit)] + public struct DWordValue + { + [FieldOffset(0)] + public Int32 Signed; + [FieldOffset(0)] + public UInt32 Unsigned; + [FieldOffset(0)] + public Single Float; + + [FieldOffset(0)] + public byte Byte0; + [FieldOffset(1)] + public byte Byte1; + [FieldOffset(2)] + public byte Byte2; + [FieldOffset(3)] + public byte Byte3; + + public DWordValue HostToNetworkOrder() { return new DWordValue { Signed = IPAddress.HostToNetworkOrder(Signed) }; } + + public static DWordValue Create(Int32 value) { return new DWordValue { Signed = value }; } + public static DWordValue Create(UInt32 value) { return new DWordValue { Unsigned = value }; } + public static DWordValue Create(Single value) { return new DWordValue { Float = value }; } + } + + [StructLayout(LayoutKind.Explicit)] + public struct QWordValue + { + [FieldOffset(0)] + public Int64 Signed; + [FieldOffset(0)] + public UInt64 Unsigned; + [FieldOffset(0)] + public Double Float; + + [FieldOffset(0)] + public byte Byte0; + [FieldOffset(1)] + public byte Byte1; + [FieldOffset(2)] + public byte Byte2; + [FieldOffset(3)] + public byte Byte3; + [FieldOffset(4)] + public byte Byte4; + [FieldOffset(5)] + public byte Byte5; + [FieldOffset(6)] + public byte Byte6; + [FieldOffset(7)] + public byte Byte7; + + public QWordValue HostToNetworkOrder() + { + if (BitConverter.IsLittleEndian) + { + return new QWordValue + { + Byte0 = Byte7, + Byte1 = Byte6, + Byte2 = Byte5, + Byte3 = Byte4, + Byte4 = Byte3, + Byte5 = Byte2, + Byte6 = Byte1, + Byte7 = Byte0, + }; + } + else + { + return this; + } + } + + public static QWordValue Create(Int64 value) { return new QWordValue { Signed = value }; } + public static QWordValue Create(UInt64 value) { return new QWordValue { Unsigned = value }; } + public static QWordValue Create(Double value) { return new QWordValue { Float = value }; } + } + } +} diff --git a/Scripts/IStore/ByteUnion.cs.meta b/Scripts/IStore/ByteUnion.cs.meta new file mode 100644 index 000000000..5f5f6d7c4 --- /dev/null +++ b/Scripts/IStore/ByteUnion.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 90602a3805f09cb46a2e25d5e9cb3cf4 +timeCreated: 1540907585 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IStore/BytesStore.cs b/Scripts/IStore/BytesStore.cs new file mode 100644 index 000000000..19ab87e6a --- /dev/null +++ b/Scripts/IStore/BytesStore.cs @@ -0,0 +1,288 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + + +namespace UniJSON +{ + public class BytesStore : IStore + { + public BytesStore() : this(64) + { } + + public BytesStore(int size) : this(new Byte[size]) + { } + + public BytesStore(Byte[] buffer) + { + m_buffer = buffer; + } + + Byte[] m_buffer; + void Require(int size) + { + if (m_buffer == null) + { + m_buffer = new Byte[Math.Max(size, 1024)]; + return; + } + + if (m_pos + size < m_buffer.Length) + { + return; + } + + var newSize = Math.Max(m_pos + size, m_buffer.Length * 2); + //Console.WriteLine(newSize); + var old = m_buffer; + m_buffer = new Byte[newSize]; + Buffer.BlockCopy(old, 0 + , m_buffer, 0, m_pos); + } + + int m_pos; + + public ArraySegment Bytes + { + get + { + return new ArraySegment(m_buffer, 0, m_pos); + } + } + + public void Clear() + { + m_pos = 0; + } + + char[] m_c = new char[1]; + public void Write(char c) + { + if (c <= 0x7F) + { + // ascii + Require(1); + m_buffer[m_pos++] = (Byte)c; + return; + } + + Require(3); + m_c[0] = c; + var size = Encoding.UTF8.GetBytes(m_c, 0, 1, m_buffer, m_pos); + m_pos += size; + } + + public void Write(string src) + { + var size = Encoding.UTF8.GetByteCount(src); + Require(size); + var byteSize = Encoding.UTF8.GetBytes(src, 0, src.Length + , m_buffer, m_pos); + if (size != byteSize) + { + throw new Exception(); + } + m_pos += byteSize; + } + + public void Write(ArraySegment bytes) + { + Require(bytes.Count); + Array.Copy(bytes.Array, bytes.Offset + , m_buffer, m_pos, bytes.Count); + m_pos += bytes.Count; + } + + public void Write(sbyte value) + { + Require(Marshal.SizeOf(value)); + m_buffer[m_pos++] = (Byte)value; + } + + public void Write(byte value) + { + Require(Marshal.SizeOf(value)); + m_buffer[m_pos++] = value; + } + + #region LittleEndian + public void WriteLittleEndian(short value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.WordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + } + + public void WriteLittleEndian(int value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.DWordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte3; + } + + public void WriteLittleEndian(long value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.QWordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte4; + m_buffer[m_pos++] = u.Byte5; + m_buffer[m_pos++] = u.Byte6; + m_buffer[m_pos++] = u.Byte7; + } + + public void WriteLittleEndian(ushort value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.WordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + } + + public void WriteLittleEndian(uint value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.DWordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte3; + } + + public void WriteLittleEndian(ulong value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.QWordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte4; + m_buffer[m_pos++] = u.Byte5; + m_buffer[m_pos++] = u.Byte6; + m_buffer[m_pos++] = u.Byte7; + } + + public void WriteLittleEndian(float value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.DWordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte3; + } + + public void WriteLittleEndian(double value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.QWordValue.Create(value); + m_buffer[m_pos++] = u.Byte0; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte4; + m_buffer[m_pos++] = u.Byte5; + m_buffer[m_pos++] = u.Byte6; + m_buffer[m_pos++] = u.Byte7; + } + #endregion + + #region BigEndian + public void WriteBigEndian(short value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.WordValue.Create(value); + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(int value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.DWordValue.Create(value); + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(long value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.QWordValue.Create(value); + m_buffer[m_pos++] = u.Byte7; + m_buffer[m_pos++] = u.Byte6; + m_buffer[m_pos++] = u.Byte5; + m_buffer[m_pos++] = u.Byte4; + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(ushort value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.WordValue.Create(value); + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(uint value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.DWordValue.Create(value); + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(ulong value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.QWordValue.Create(value); + m_buffer[m_pos++] = u.Byte7; + m_buffer[m_pos++] = u.Byte6; + m_buffer[m_pos++] = u.Byte5; + m_buffer[m_pos++] = u.Byte4; + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(float value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.DWordValue.Create(value); + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + + public void WriteBigEndian(double value) + { + Require(Marshal.SizeOf(value)); + var u = ByteUnion.QWordValue.Create(value); + m_buffer[m_pos++] = u.Byte7; + m_buffer[m_pos++] = u.Byte6; + m_buffer[m_pos++] = u.Byte5; + m_buffer[m_pos++] = u.Byte4; + m_buffer[m_pos++] = u.Byte3; + m_buffer[m_pos++] = u.Byte2; + m_buffer[m_pos++] = u.Byte1; + m_buffer[m_pos++] = u.Byte0; + } + #endregion + } +} diff --git a/Scripts/IStore/BytesStore.cs.meta b/Scripts/IStore/BytesStore.cs.meta new file mode 100644 index 000000000..c41985875 --- /dev/null +++ b/Scripts/IStore/BytesStore.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d49a52418427394499c901cb23f13d30 +timeCreated: 1540907458 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IStore/IStore.cs b/Scripts/IStore/IStore.cs new file mode 100644 index 000000000..2144e3ba7 --- /dev/null +++ b/Scripts/IStore/IStore.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +namespace UniJSON +{ + public interface IStore + { + void Clear(); + ArraySegment Bytes { get; } + + void Write(Byte value); + void Write(SByte value); + + // network + void WriteBigEndian(UInt16 value); + void WriteBigEndian(UInt32 value); + void WriteBigEndian(UInt64 value); + void WriteBigEndian(Int16 value); + void WriteBigEndian(Int32 value); + void WriteBigEndian(Int64 value); + void WriteBigEndian(Single value); + void WriteBigEndian(Double value); + + // intel cpu + void WriteLittleEndian(UInt16 value); + void WriteLittleEndian(UInt32 value); + void WriteLittleEndian(UInt64 value); + void WriteLittleEndian(Int16 value); + void WriteLittleEndian(Int32 value); + void WriteLittleEndian(Int64 value); + void WriteLittleEndian(Single value); + void WriteLittleEndian(Double value); + + void Write(ArraySegment bytes); + + void Write(string src); + void Write(char c); + } + + public static class IStoreExtensions + { + public static void WriteValues(this IStore s, params Byte[] bytes) + { + s.Write(new ArraySegment(bytes)); + } + + public static void Write(this IStore s, Byte[] bytes) + { + s.Write(new ArraySegment(bytes)); + } + + public static void Write(this IStore s, IEnumerable bytes) + { + s.Write(new ArraySegment(bytes.ToArray())); + } + + public static Utf8String ToUtf8String(this IStore s) + { + return new Utf8String(s.Bytes); + } + } +} diff --git a/Scripts/IStore/IStore.cs.meta b/Scripts/IStore/IStore.cs.meta new file mode 100644 index 000000000..7f17e8f8e --- /dev/null +++ b/Scripts/IStore/IStore.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 558419bba2d829e4884fca9c2046fc3c +timeCreated: 1495517075 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IStore/StreamStore.cs b/Scripts/IStore/StreamStore.cs new file mode 100644 index 000000000..143c5a771 --- /dev/null +++ b/Scripts/IStore/StreamStore.cs @@ -0,0 +1,149 @@ +using System; +using System.IO; +using System.Text; + +namespace UniJSON +{ + public class StreamStore: IStore + { + Stream m_s; + BinaryWriter m_w; + + public StreamStore(Stream s) + { + m_s = s; + m_w = new BinaryWriter(m_s); + } + + public ArraySegment Bytes + { + get + { +#if NETFX_CORE + throw new NotImplementedException(); +#else + var ms = m_s as MemoryStream; + if (ms == null) + { + throw new NotImplementedException(); + } + return new ArraySegment(ms.GetBuffer(), 0, (int)ms.Position); +#endif + } + } + + public void Clear() + { + m_s.SetLength(0); + } + + public void Write(sbyte value) + { + m_w.Write(value); + } + + public void Write(byte value) + { + m_w.Write(value); + } + + public void Write(char c) + { + m_w.Write(c); + } + + public void Write(string src) + { + m_w.Write(Encoding.UTF8.GetBytes(src)); + } + + public void Write(ArraySegment bytes) + { + m_w.Write(bytes.Array, bytes.Offset, bytes.Count); + } + +#region BigEndian + public void WriteBigEndian(int value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(float value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(double value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(long value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(short value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(uint value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(ulong value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(ushort value) + { + throw new NotImplementedException(); + } +#endregion + +#region LittleEndian + public void WriteLittleEndian(long value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(uint value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(short value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(ulong value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(double value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(float value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(int value) + { + m_w.Write(value); + } + + public void WriteLittleEndian(ushort value) + { + m_w.Write(value); + } +#endregion + } +} diff --git a/Scripts/IStore/StreamStore.cs.meta b/Scripts/IStore/StreamStore.cs.meta new file mode 100644 index 000000000..accce847c --- /dev/null +++ b/Scripts/IStore/StreamStore.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b87313b5306b62d4ea4f743055ae60f4 +timeCreated: 1495517079 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IStore/StringBuilderStore.cs b/Scripts/IStore/StringBuilderStore.cs new file mode 100644 index 000000000..8c8875c4f --- /dev/null +++ b/Scripts/IStore/StringBuilderStore.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Text; + + +namespace UniJSON +{ + public class StringBuilderStore: IStore + { + StringBuilder m_sb; + + public StringBuilderStore(StringBuilder sb) + { + m_sb = sb; + } + + public ArraySegment Bytes + { + get + { + return new ArraySegment( + Encoding.UTF8.GetBytes(Buffer()) + ); + } + } + + public string Buffer() + { + return m_sb.ToString(); + } + + public void Clear() + { + m_sb.Length = 0; + } + + public void Write(ArraySegment bytes) + { + var text = Encoding.UTF8.GetString(bytes.Array, bytes.Offset, bytes.Count); + Write(text); + } + + public void Write(byte value) + { + throw new NotImplementedException(); + } + + public void Write(sbyte value) + { + throw new NotImplementedException(); + } + + public void Write(IEnumerable src) + { + foreach(var c in src) + { + m_sb.Append(c); + } + } + public void Write(Char c) + { + m_sb.Append(c); + } + public void Write(string src) + { + m_sb.Append(src); + } + + #region BigEndian + public void WriteBigEndian(int value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(float value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(double value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(long value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(ulong value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(short value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(uint value) + { + throw new NotImplementedException(); + } + + public void WriteBigEndian(ushort value) + { + throw new NotImplementedException(); + } + #endregion + + #region LittleEndian + public void WriteLittleEndian(double value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(short value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(int value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(float value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(long value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(ulong value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(uint value) + { + throw new NotImplementedException(); + } + + public void WriteLittleEndian(ushort value) + { + throw new NotImplementedException(); + } + #endregion + } +} diff --git a/Scripts/IStore/StringBuilderStore.cs.meta b/Scripts/IStore/StringBuilderStore.cs.meta new file mode 100644 index 000000000..f3290cf78 --- /dev/null +++ b/Scripts/IStore/StringBuilderStore.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 74639d64f5620dd45a1a8edc65f48aab +timeCreated: 1495517076 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ITreeNode.cs b/Scripts/ITreeNode.cs new file mode 100644 index 000000000..e98a0207c --- /dev/null +++ b/Scripts/ITreeNode.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + + +namespace UniJSON +{ + public interface ITreeNode + where T : ITreeNode + { + bool IsValid { get; } + + bool HasParent { get; } + T Parent { get; } + IEnumerable Children { get; } + + int ValueIndex { get; } + U Value { get; } + void SetValue(U value); + } + + public interface IListTreeItem + { + int ParentIndex { get; } + } +} diff --git a/Scripts/ITreeNode.cs.meta b/Scripts/ITreeNode.cs.meta new file mode 100644 index 000000000..fc63b3d17 --- /dev/null +++ b/Scripts/ITreeNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: baf3ade828d6e4c429d402b486911774 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/IValue.cs b/Scripts/IValue.cs new file mode 100644 index 000000000..024589819 --- /dev/null +++ b/Scripts/IValue.cs @@ -0,0 +1,42 @@ +using System; + + +namespace UniJSON +{ + public enum ValueNodeType + { + Null, + Boolean, + String, + Binary, + Integer, + Number, + Array, + Object, + NaN, + Infinity, + MinusInfinity, + } + + public interface IValue + { + T New(ArraySegment bytes, ValueNodeType valueType, int parentIndex); + T Key(Utf8String key, int parentIndex); + ValueNodeType ValueType { get; } + ArraySegment Bytes { get; } + Boolean GetBoolean(); + String GetString(); + Utf8String GetUtf8String(); + SByte GetSByte(); + Int16 GetInt16(); + Int32 GetInt32(); + Int64 GetInt64(); + Byte GetByte(); + UInt16 GetUInt16(); + UInt32 GetUInt32(); + UInt64 GetUInt64(); + Single GetSingle(); + Double GetDouble(); + U GetValue(); + } +} diff --git a/Scripts/IValue.cs.meta b/Scripts/IValue.cs.meta new file mode 100644 index 000000000..32389b8b8 --- /dev/null +++ b/Scripts/IValue.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4737055a37e47074e92e6fc03a96a9a5 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json.meta b/Scripts/Json.meta new file mode 100644 index 000000000..b2b05c2e0 --- /dev/null +++ b/Scripts/Json.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f4bf1a4860dc23244837e31091692c3c +folderAsset: yes +timeCreated: 1540897217 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonDiff.cs b/Scripts/Json/JsonDiff.cs new file mode 100644 index 000000000..d6491a25d --- /dev/null +++ b/Scripts/Json/JsonDiff.cs @@ -0,0 +1,44 @@ +using System; + +namespace UniJSON +{ + public enum JsonDiffType + { + KeyAdded, + KeyRemoved, + ValueChanged, + } + + public struct JsonDiff + { + public JsonPointer Path; + public JsonDiffType DiffType; + public string Msg; + + public static JsonDiff Create(ListTreeNode node, JsonDiffType diffType, string msg) + where T: IListTreeItem, IValue + { + return new JsonDiff + { + Path = JsonPointer.Create(node), + DiffType = diffType, + Msg = msg, + }; + } + + public override string ToString() + { + switch (DiffType) + { + case JsonDiffType.KeyAdded: + return string.Format("+ {0}: {1}", Path, Msg); + case JsonDiffType.KeyRemoved: + return string.Format("- {0}: {1}", Path, Msg); + case JsonDiffType.ValueChanged: + return string.Format("= {0}: {1}", Path, Msg); + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/Scripts/Json/JsonDiff.cs.meta b/Scripts/Json/JsonDiff.cs.meta new file mode 100644 index 000000000..3c221f2f4 --- /dev/null +++ b/Scripts/Json/JsonDiff.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 97356eb7e23aca64c84f836d6c298f43 +timeCreated: 1543427903 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonFormatter.cs b/Scripts/Json/JsonFormatter.cs new file mode 100644 index 000000000..4764ccd33 --- /dev/null +++ b/Scripts/Json/JsonFormatter.cs @@ -0,0 +1,546 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + + +namespace UniJSON +{ + public class JsonFormatter : IFormatter, IRpc + { + IStore m_w; + protected IStore Store + { + get { return m_w; } + } + + enum Current + { + ROOT, + ARRAY, + OBJECT + } + + class Context + { + public Current Current; + public int Count; + + public Context(Current current) + { + Current = current; + Count = 0; + } + } + + Stack m_stack = new Stack(); + + string m_indent; + void Indent() + { + if (!string.IsNullOrEmpty(m_indent)) + { + m_w.Write('\n'); + for (int i = 0; i < m_stack.Count - 1; ++i) + { + m_w.Write(m_indent); + } + } + } + + string m_colon; + + public JsonFormatter(int indent = 0) + : this(new BytesStore(128), indent) + { + } + + public JsonFormatter(IStore w, int indent = 0) + { + m_w = w; + m_stack.Push(new Context(Current.ROOT)); + m_indent = new string(Enumerable.Range(0, indent).Select(x => ' ').ToArray()); + m_colon = indent == 0 ? ":" : ": "; + } + + public override string ToString() + { + var bytes = this.GetStoreBytes(); + return Encoding.UTF8.GetString(bytes.Array, bytes.Offset, bytes.Count); + } + + public IStore GetStore() + { + return m_w; + } + + public void Clear() + { + m_w.Clear(); + m_stack.Clear(); + m_stack.Push(new Context(Current.ROOT)); + } + + protected void CommaCheck(bool isKey = false) + { + var top = m_stack.Pop(); + switch (top.Current) + { + case Current.ROOT: + { + if (top.Count != 0) throw new FormatterException("multiple root value"); + } + break; + + case Current.ARRAY: + { + if (top.Count != 0) + { + m_w.Write(','); + } + } + break; + + case Current.OBJECT: + { + if (top.Count % 2 == 0) + { + if (!isKey) throw new FormatterException("key exptected"); + if (top.Count != 0) + { + m_w.Write(','); + } + } + else + { + if (isKey) throw new FormatterException("key not exptected"); + } + } + break; + } + top.Count += 1; + /* + { + var debug = string.Format("{0} {1} = {2}", m_stack.Count, top.Current, top.Count); + Debug.Log(debug); + } + */ + m_stack.Push(top); + } + + static Utf8String s_null = Utf8String.From("null"); + public void Null() + { + CommaCheck(); + m_w.Write(s_null.Bytes); + } + + public void BeginList(int _ = 0) + { + CommaCheck(); + m_w.Write('['); + m_stack.Push(new Context(Current.ARRAY)); + } + + public void EndList() + { + if (m_stack.Peek().Current != Current.ARRAY) + { + throw new InvalidOperationException(); + } + m_w.Write(']'); + m_stack.Pop(); + } + + public void BeginMap(int _ = 0) + { + CommaCheck(); + m_w.Write('{'); + m_stack.Push(new Context(Current.OBJECT)); + } + + public void EndMap() + { + if (m_stack.Peek().Current != Current.OBJECT) + { + throw new InvalidOperationException(); + } + m_stack.Pop(); + Indent(); + m_w.Write('}'); + } + + public void Key(Utf8String key) + { + _Value(key, true); + m_w.Write(m_colon); + } + + public void Value(string x) + { + Value(Utf8String.From(x)); + } + + public void Value(Utf8String key) + { + _Value(key, false); + } + + void _Value(Utf8String key, bool isKey) + { + CommaCheck(isKey); + if (isKey) + { + Indent(); + } + JsonString.Quote(key, m_w); + } + + static Utf8String s_true = Utf8String.From("true"); + static Utf8String s_false = Utf8String.From("false"); + public void Value(Boolean x) + { + CommaCheck(); + m_w.Write(x ? s_true.Bytes : s_false.Bytes); + } + + public void Value(SByte x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + public void Value(Int16 x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + public void Value(Int32 x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + public void Value(Int64 x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + + public void Value(Byte x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + public void Value(UInt16 x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + public void Value(UInt32 x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + public void Value(UInt64 x) + { + CommaCheck(); + m_w.Write(x.ToString()); + } + + public void Value(Single x) + { + CommaCheck(); + m_w.Write(x.ToString("R", CultureInfo.InvariantCulture)); + } + public void Value(Double x) + { + CommaCheck(); + m_w.Write(x.ToString("R", CultureInfo.InvariantCulture)); + } + + public void Value(ArraySegment x) + { + CommaCheck(); + m_w.Write('"'); + m_w.Write(Convert.ToBase64String(x.Array, x.Offset, x.Count)); + m_w.Write('"'); + } + + // ISO-8601: YYYY-MM-DD“T”hh:mm:ss“Z” + public void Value(DateTimeOffset x) + { + Value(x.ToString("yyyy-MM-ddTHH:mm:ssZ")); + } + + public void Value(ListTreeNode node) + { + CommaCheck(); + m_w.Write(node.Value.Bytes); + } + + #region IRpc + int m_nextRequestId = 1; + + static Utf8String s_jsonrpc = Utf8String.From("jsonrpc"); + static Utf8String s_20 = Utf8String.From("2.0"); + static Utf8String s_method = Utf8String.From("method"); + static Utf8String s_params = Utf8String.From("params"); + + public void Notify(Utf8String method) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + } + EndList(); + EndMap(); + } + + public void Notify(Utf8String method, A0 a0) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + } + EndList(); + EndMap(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + } + EndList(); + EndMap(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + } + EndList(); + EndMap(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + this.Serialize(a3); + } + EndList(); + EndMap(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + this.Serialize(a3); + this.Serialize(a4); + } + EndList(); + EndMap(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + this.Serialize(a3); + this.Serialize(a4); + this.Serialize(a5); + } + EndList(); + EndMap(); + } + + static Utf8String s_id = Utf8String.From("id"); + + public void Request(Utf8String method) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + } + EndList(); + EndMap(); + } + + public void Request(Utf8String method, + A0 a0) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + } + EndList(); + EndMap(); + } + + public void Request(Utf8String method, + A0 a0, A1 a1) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + } + EndList(); + EndMap(); + } + + public void Request(Utf8String method, + A0 a0, A1 a1, A2 a2) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + } + EndList(); + EndMap(); + } + + public void Request(Utf8String method, + A0 a0, A1 a1, A2 a2, A3 a3) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + this.Serialize(a3); + } + EndList(); + EndMap(); + } + + public void Request(Utf8String method, + A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + this.Serialize(a3); + this.Serialize(a4); + } + EndList(); + EndMap(); + } + + public void Request(Utf8String method, + A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(m_nextRequestId++); + Key(s_method); Value(method); + Key(s_params); BeginList(); + { + this.Serialize(a0); + this.Serialize(a1); + this.Serialize(a2); + this.Serialize(a3); + this.Serialize(a4); + this.Serialize(a5); + } + EndList(); + EndMap(); + } + + static Utf8String s_error = Utf8String.From("error"); + + public void ResponseError(int id, Exception error) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(id); + Key(s_error); this.Serialize(error); + EndMap(); + } + + static Utf8String s_result = Utf8String.From("result"); + + public void ResponseSuccess(int id) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(id); + Key(s_result); Null(); + EndMap(); + } + + public void ResponseSuccess(int id, T result) + { + BeginMap(); + Key(s_jsonrpc); Value(s_20); + Key(s_id); Value(id); + Key(s_result); this.Serialize(result); + EndMap(); + } + #endregion + } +} diff --git a/Scripts/Json/JsonFormatter.cs.meta b/Scripts/Json/JsonFormatter.cs.meta new file mode 100644 index 000000000..230469e58 --- /dev/null +++ b/Scripts/Json/JsonFormatter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9968766fe6cce164a8c7e950200cbb11 +timeCreated: 1495517078 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonParser.cs b/Scripts/Json/JsonParser.cs new file mode 100644 index 000000000..e7fea529e --- /dev/null +++ b/Scripts/Json/JsonParser.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections.Generic; + + +namespace UniJSON +{ + public class JsonParseResult + { + public List Values = new List(); + } + + public static class JsonParser + { + static ValueNodeType GetValueType(Utf8String segment) + { + switch (Char.ToLower((char)segment[0])) + { + case '{': return ValueNodeType.Object; + case '[': return ValueNodeType.Array; + case '"': return ValueNodeType.String; + case 't': return ValueNodeType.Boolean; + case 'f': return ValueNodeType.Boolean; + case 'n': + if (segment.ByteLength >= 2 && Char.ToLower((char) segment[1]) == 'a') + { + return ValueNodeType.NaN; + } + + return ValueNodeType.Null; + + case 'i': + return ValueNodeType.Infinity; + + case '-': + if (segment.ByteLength >= 2 && Char.ToLower((char) segment[1]) == 'i') + { + return ValueNodeType.MinusInfinity; + } + goto case '0';// fall through + case '0': // fall through + case '1': // fall through + case '2': // fall through + case '3': // fall through + case '4': // fall through + case '5': // fall through + case '6': // fall through + case '7': // fall through + case '8': // fall through + case '9': // fall through + { + if (segment.IsInt) + { + return ValueNodeType.Integer; + } + else + { + return ValueNodeType.Number; + } + } + + default: + throw new ParserException(segment + " is not valid json start"); + } + } + + /// + /// Expected null, boolean, integer, number + /// + /// + /// + /// + /// + static JsonValue ParsePrimitive(Utf8String segment, ValueNodeType valueType, int parentIndex) + { + int i = 1; + for (; i < segment.ByteLength; ++i) + { + if (Char.IsWhiteSpace((char)segment[i]) + || segment[i] == '}' + || segment[i] == ']' + || segment[i] == ',' + || segment[i] == ':' + ) + { + break; + } + } + return new JsonValue(segment.Subbytes(0, i), valueType, parentIndex); + } + + static JsonValue ParseString(Utf8String segment, int parentIndex) + { + int pos; + if (segment.TrySearchAscii((Byte)'"', 1, out pos)) + { + return new JsonValue(segment.Subbytes(0, pos + 1), ValueNodeType.String, parentIndex); + } + else + { + throw new ParserException("no close string: " + segment); + } + } + + static Utf8String ParseArray(Utf8String segment, List values, int parentIndex) + { + var closeChar = ']'; + bool isFirst = true; + var current = segment.Subbytes(1); + while (true) + { + { + // skip white space + int nextToken; + if (!current.TrySearchByte(x => !Char.IsWhiteSpace((char)x), out nextToken)) + { + throw new ParserException("no white space expected"); + } + current = current.Subbytes(nextToken); + } + + { + if (current[0] == closeChar) + { + // end + break; + } + } + + if (isFirst) + { + isFirst = false; + } + else + { + // search ',' or closeChar + int keyPos; + if (!current.TrySearchByte(x => x == ',', out keyPos)) + { + throw new ParserException("',' expected"); + } + current = current.Subbytes(keyPos + 1); + } + + { + // skip white space + int nextToken; + if (!current.TrySearchByte(x => !Char.IsWhiteSpace((char)x), out nextToken)) + { + throw new ParserException("not whitespace expected"); + } + current = current.Subbytes(nextToken); + } + + // value + var value = Parse(current, values, parentIndex); + current = current.Subbytes(value.Segment.ByteLength); + } + + return current; + } + + static Utf8String ParseObject(Utf8String segment, List values, int parentIndex) + { + var closeChar = '}'; + bool isFirst = true; + var current = segment.Subbytes(1); + while (true) + { + { + // skip white space + int nextToken; + if (!current.TrySearchByte(x => !Char.IsWhiteSpace((char)x), out nextToken)) + { + throw new ParserException("no white space expected"); + } + current = current.Subbytes(nextToken); + } + + { + if (current[0] == closeChar) + { + break; + } + } + + if (isFirst) + { + isFirst = false; + } + else + { + // search ',' or closeChar + int keyPos; + if (!current.TrySearchByte(x => x == ',', out keyPos)) + { + throw new ParserException("',' expected"); + } + current = current.Subbytes(keyPos + 1); + } + + { + // skip white space + int nextToken; + if (!current.TrySearchByte(x => !Char.IsWhiteSpace((char)x), out nextToken)) + { + throw new ParserException("not whitespace expected"); + } + current = current.Subbytes(nextToken); + } + + // key + var key = Parse(current, values, parentIndex); + if (key.ValueType != ValueNodeType.String) + { + throw new ParserException("object key must string: " + key.Segment); + } + current = current.Subbytes(key.Segment.ByteLength); + + // search ':' + int valuePos; + if (!current.TrySearchByte(x => x == ':', out valuePos)) + { + throw new ParserException(": is not found"); + } + current = current.Subbytes(valuePos + 1); + + { + // skip white space + int nextToken; + if (!current.TrySearchByte(x => !Char.IsWhiteSpace((char)x), out nextToken)) + { + throw new ParserException("not whitespace expected"); + } + current = current.Subbytes(nextToken); + } + + // value + var value = Parse(current, values, parentIndex); + current = current.Subbytes(value.Segment.ByteLength); + } + + return current; + } + + static JsonValue Parse(Utf8String segment, List values, int parentIndex) + { + // skip white space + int pos; + if (!segment.TrySearchByte(x => !char.IsWhiteSpace((char)x), out pos)) + { + throw new ParserException("only whitespace"); + } + segment = segment.Subbytes(pos); + + var valueType = GetValueType(segment); + switch (valueType) + { + case ValueNodeType.Boolean: + case ValueNodeType.Integer: + case ValueNodeType.Number: + case ValueNodeType.Null: + case ValueNodeType.NaN: + case ValueNodeType.Infinity: + case ValueNodeType.MinusInfinity: + { + var value= ParsePrimitive(segment, valueType, parentIndex); + values.Add(value); + return value; + } + + case ValueNodeType.String: + { + var value= ParseString(segment, parentIndex); + values.Add(value); + return value; + } + + case ValueNodeType.Array: // fall through + { + var index = values.Count; + values.Add(new JsonValue()); // placeholder + var current = ParseArray(segment, values, index); + values[index] = new JsonValue(segment.Subbytes(0, current.Bytes.Offset + 1 - segment.Bytes.Offset), + ValueNodeType.Array, parentIndex); + return values[index]; + } + + case ValueNodeType.Object: // fall through + { + var index = values.Count; + values.Add(new JsonValue()); // placeholder + var current=ParseObject(segment, values, index); + values[index] = new JsonValue(segment.Subbytes(0, current.Bytes.Offset + 1 - segment.Bytes.Offset), + ValueNodeType.Object, parentIndex); + return values[index]; + } + + default: + throw new NotImplementedException(); + } + } + + public static ListTreeNode Parse(String json) + { + return Parse(Utf8String.From(json)); + } + + public static ListTreeNode Parse(Utf8String json) + { + var result = new List(); + var value = Parse(json, result, -1); + if (value.ValueType != ValueNodeType.Array && value.ValueType != ValueNodeType.Object) + { + result.Add(value); + return new ListTreeNode(result); + } + else + { + return new ListTreeNode(result); + } + } + } +} diff --git a/Scripts/Json/JsonParser.cs.meta b/Scripts/Json/JsonParser.cs.meta new file mode 100644 index 000000000..bcc3cf400 --- /dev/null +++ b/Scripts/Json/JsonParser.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3ab6245869fe6f7448aa8f4e84286cdd +timeCreated: 1526137862 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonPointer.cs b/Scripts/Json/JsonPointer.cs new file mode 100644 index 000000000..26ba410b5 --- /dev/null +++ b/Scripts/Json/JsonPointer.cs @@ -0,0 +1,101 @@ +using System; +using System.Linq; +using System.Text; + + +namespace UniJSON +{ + public struct JsonPointer + { + public ArraySegment Path + { + get; + private set; + } + + public int Count + { + get + { + return Path.Count; + } + } + + public Utf8String this[int index] + { + get + { + return Path.Array[Path.Offset + index]; + } + } + + public JsonPointer Unshift() + { + return new JsonPointer + { + Path = new ArraySegment(Path.Array, Path.Offset + 1, Path.Count - 1) + }; + } + + public static JsonPointer Create(ListTreeNode node) + where T : IListTreeItem, IValue + { + return new JsonPointer + { + Path = new ArraySegment(node.Path().Skip(1).Select(x => GetKeyFromParent(x)).ToArray()) + }; + } + + public JsonPointer(Utf8String pointer) : this() + { + int pos; + if (!pointer.TrySearchAscii((Byte)'/', 0, out pos)) + { + throw new ArgumentException(); + } + if (pos != 0) + { + throw new ArgumentException(); + } + + var splited = pointer.Split((Byte)'/').ToArray(); + Path = new ArraySegment(splited, 1, splited.Length - 1); + } + + public override string ToString() + { + if (Path.Count == 0) + { + return "/"; + } + + var sb = new StringBuilder(); + var end = Path.Offset + Path.Count; + for (int i = Path.Offset; i < end; ++i) + { + sb.Append('/'); + sb.Append(Path.Array[i]); + } + return sb.ToString(); + } + + static Utf8String GetKeyFromParent(ListTreeNode json) + where T : IListTreeItem, IValue + { + var parent = json.Parent; + if (parent.IsArray()) + { + var index = parent.IndexOf(json); + return Utf8String.From(index); + } + else if (parent.IsMap()) + { + return parent.KeyOf(json); + } + else + { + throw new NotImplementedException(); + } + } + } +} diff --git a/Scripts/Json/JsonPointer.cs.meta b/Scripts/Json/JsonPointer.cs.meta new file mode 100644 index 000000000..c672f6aa4 --- /dev/null +++ b/Scripts/Json/JsonPointer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8b7033668ce791e40819d16e664efe18 +timeCreated: 1543321766 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonSchema.cs b/Scripts/Json/JsonSchema.cs new file mode 100644 index 000000000..d563fd37c --- /dev/null +++ b/Scripts/Json/JsonSchema.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace UniJSON +{ + public class JsonSchema : IEquatable + { + public string Schema; // http://json-schema.org/draft-04/schema + + #region Annotations + string m_title; + public string Title + { + get { return m_title; } + private set + { + if (value == null) + { + m_title = ""; + } + else + { + m_title = value.Trim(); + } + } + } + + string m_desc; + public string Description + { + get { return m_desc; } + private set + { + if (value == null) + { + m_desc = ""; + } + else + { + m_desc = value.Trim(); + } + } + } + + public object Default + { + get; + private set; + } + #endregion + + public IJsonSchemaValidator Validator { get; set; } + + /// + /// Skip validator comparison + /// + public bool SkipComparison { get; set; } + + public override string ToString() + { + return string.Format("<{0}>", Title); + } + + public override int GetHashCode() + { + return 1; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonSchema; + if (rhs == null) return false; + return Equals(rhs); + } + + public bool Equals(JsonSchema rhs) + { + // skip comparison + if (SkipComparison) return true; + if (rhs.SkipComparison) return true; + return Validator.Equals(rhs.Validator); + } + + public static bool operator ==(JsonSchema obj1, JsonSchema obj2) + { + if (ReferenceEquals(obj1, obj2)) + { + return true; + } + + if (ReferenceEquals(obj1, null)) + { + return false; + } + + if (ReferenceEquals(obj2, null)) + { + return false; + } + + return obj1.Equals(obj2); + } + + public static bool operator !=(JsonSchema obj1, JsonSchema obj2) + { + return !(obj1 == obj2); + } + + #region FromType + public static JsonSchema FromType() + { + return FromType(typeof(T), null, null); + } + + public static JsonSchema FromType(Type t, + BaseJsonSchemaAttribute a = null, // field attribute + ItemJsonSchemaAttribute ia = null + ) + { + // class attribute + var aa = t.GetCustomAttributes(typeof(JsonSchemaAttribute), true) + .FirstOrDefault() as JsonSchemaAttribute; + if (a != null) + { + a.Merge(aa); + } + else + { + if (aa == null) + { + a = new JsonSchemaAttribute(); + } + else + { + a = aa; + } + } + + if (ia == null) + { + ia = t.GetCustomAttributes(typeof(ItemJsonSchemaAttribute), true) + .FirstOrDefault() as ItemJsonSchemaAttribute; + } + + IJsonSchemaValidator validator = null; + bool skipComparison = a.SkipSchemaComparison; + if (t == typeof(object)) + { + skipComparison = true; + } + + if (a.EnumValues != null) + { + try + { + validator = JsonEnumValidator.Create(a.EnumValues, a.EnumSerializationType); + } + catch (Exception) + { + throw new Exception(String.Join(", ", a.EnumValues.Select(x => x.ToString()).ToArray())); + } + } + else if (t.IsEnum) + { + validator = JsonEnumValidator.Create(t, a.EnumSerializationType, a.EnumExcludes); + } + else + { + validator = JsonSchemaValidatorFactory.Create(t, a, ia); + } + + var schema = new JsonSchema + { + Title = a.Title, + Description = a.Description, + Validator = validator, + SkipComparison = skipComparison + }; + + return schema; + } + #endregion + + #region FromJson + static ValueNodeType ParseValueType(string type) + { + try + { + return (ValueNodeType)Enum.Parse(typeof(ValueNodeType), type, true); + } + catch (ArgumentException) + { + throw new ArgumentException(string.Format("unknown type: {0}", type)); + } + } + + Stack m_context = new Stack(); + + static Utf8String s_ref = Utf8String.From("$ref"); + + public void Parse(IFileSystemAccessor fs, ListTreeNode root, string Key) + { + m_context.Push(Key); + + var compositionType = default(CompositionType); + var composition = new List(); + foreach (var kv in root.ObjectItems()) + { + switch (kv.Key.GetString()) + { + case "$schema": + Schema = kv.Value.GetString(); + break; + + case "$ref": + { + var refFs = fs.Get(kv.Value.GetString()); + + // parse JSON + var json = refFs.ReadAllText(); + var refRoot = JsonParser.Parse(json); + + Parse(refFs, refRoot, "$ref"); + } + break; + + #region Annotation + case "title": + Title = kv.Value.GetString(); + break; + + case "description": + Description = kv.Value.GetString(); + break; + + case "default": + Default = kv.Value; + break; + #endregion + + #region Validation + // http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1 + case "type": + if (Validator == null) + { + Validator = JsonSchemaValidatorFactory.Create(kv.Value.GetString()); + } + break; + + case "enum": + Validator = JsonEnumValidator.Create(kv.Value); + break; + + case "const": + break; + #endregion + + #region Composite + // http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.7 + case "oneOf": + break; + + case "not": + break; + + case "anyOf": // composition + case "allOf": // composition + { + compositionType = (CompositionType)Enum.Parse(typeof(CompositionType), kv.Key.GetString(), true); + foreach (var item in kv.Value.ArrayItems()) + { + if (item.ContainsKey(s_ref)) + { + var sub = JsonSchema.ParseFromPath(fs.Get(item[s_ref].GetString())); + composition.Add(sub); + } + else + { + var sub = new JsonSchema(); + sub.Parse(fs, item, compositionType.ToString()); + composition.Add(sub); + } + } + Composite(compositionType, composition); + } + break; + #endregion + + // http://json-schema.org/latest/json-schema-validation.html#rfc.section.7 + case "format": + break; + + #region Gltf + case "gltf_detailedDescription": + break; + + case "gltf_webgl": + break; + + case "gltf_uriType": + break; + #endregion + + default: + { + if (Validator != null) + { + if (Validator.FromJsonSchema(fs, kv.Key.GetString(), kv.Value)) + { + continue; + } + } + throw new NotImplementedException(string.Format("unknown key: {0}", kv.Key)); + } + } + } + m_context.Pop(); + + if (Validator == null) + { + SkipComparison = true; + } + } + + void Composite(CompositionType compositionType, List composition) + { + switch (compositionType) + { + case CompositionType.AllOf: + if (composition.Count == 1) + { + // inheritance + if (Validator == null) + { + //Validator = JsonSchemaValidatorFactory.Create(composition[0].Validator.ValueNodeType); + Validator = composition[0].Validator; + } + else + { + Validator.Merge(composition[0].Validator); + } + } + else + { + throw new NotImplementedException(); + } + break; + + case CompositionType.AnyOf: + if (Validator == null) + { + if (composition.Count == 1) + { + throw new NotImplementedException(); + //Validator = composition[0].Validator; + } + else + { + // extend enum + // enum, enum..., type + Validator = JsonEnumValidator.Create(composition, EnumSerializationType.AsString); + } + } + //throw new NotImplementedException(); + break; + + default: + throw new NotImplementedException(); + } + } + + public static JsonSchema ParseFromPath(IFileSystemAccessor fs) + { + // parse JSON + var json = fs.ReadAllText(); + var root = JsonParser.Parse(json); + + // create schema + var schema = new JsonSchema(); + schema.Parse(fs, root, "__ParseFromPath__" + fs.ToString()); + return schema; + } + #endregion + + public void Serialize(IFormatter f, T o) + { + var c = new JsonSchemaValidationContext(o); + + var ex = Validator.Validate(c, o); + if (ex != null) + { + throw ex; + } + + Validator.Serialize(f, c, o); + } + + public void ToJson(IFormatter f) + { + f.BeginMap(2); + if (!string.IsNullOrEmpty(Title)) { f.Key("title"); f.Value(Title); } + if (!string.IsNullOrEmpty(Description)) { f.Key("description"); f.Value(Description); } + Validator.ToJsonScheama(f); + f.EndMap(); + } + } + + public static class JsonSchemaExtensions + { + public static string Serialize(this JsonSchema s, T o) + { + var f = new JsonFormatter(); + s.Serialize(f, o); + return f.ToString(); + } + } +} diff --git a/Scripts/Json/JsonSchema.cs.meta b/Scripts/Json/JsonSchema.cs.meta new file mode 100644 index 000000000..05431a7f6 --- /dev/null +++ b/Scripts/Json/JsonSchema.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4d98ef4e469916e428284c9155f29059 +timeCreated: 1526056149 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonSchemaAttribute.cs b/Scripts/Json/JsonSchemaAttribute.cs new file mode 100644 index 000000000..7cd7ac3c0 --- /dev/null +++ b/Scripts/Json/JsonSchemaAttribute.cs @@ -0,0 +1,72 @@ +using System; + + +namespace UniJSON +{ + public enum EnumSerializationType + { + AsInt, + AsString, + AsLowerString, + AsUpperString, + } + + public class BaseJsonSchemaAttribute : Attribute + { + #region Annotation + public string Title; + public string Description; + #endregion + + #region integer, number + public double Minimum = double.NaN; + public bool ExclusiveMinimum; + public double Maximum = double.NaN; + public bool ExclusiveMaximum; + public double MultipleOf; + #endregion + + #region string + public string Pattern; + #endregion + + #region array + public int MinItems; + public int MaxItems; + #endregion + + #region object + public ValueNodeType ValueType; + public int MinProperties; + public bool Required; + public string[] Dependencies; + #endregion + + #region enum + public EnumSerializationType EnumSerializationType; + public object[] EnumValues; + public object[] EnumExcludes; + #endregion + + public PropertyExportFlags ExportFlags = PropertyExportFlags.Default; + + /// + /// skip validator comparison + /// + public bool SkipSchemaComparison; + + public void Merge(BaseJsonSchemaAttribute rhs) + { + if (rhs == null) return; + + if (string.IsNullOrEmpty(Title)) + { + Title = rhs.Title; + } + } + } + + public class JsonSchemaAttribute : BaseJsonSchemaAttribute { } + + public class ItemJsonSchemaAttribute : BaseJsonSchemaAttribute { } +} diff --git a/Scripts/Json/JsonSchemaAttribute.cs.meta b/Scripts/Json/JsonSchemaAttribute.cs.meta new file mode 100644 index 000000000..fa872cf7e --- /dev/null +++ b/Scripts/Json/JsonSchemaAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e79a9be81d4b0fc4ebd9ca47d0f20a04 +timeCreated: 1526058096 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonString.cs b/Scripts/Json/JsonString.cs new file mode 100644 index 000000000..c352dfb5c --- /dev/null +++ b/Scripts/Json/JsonString.cs @@ -0,0 +1,372 @@ +using System; +using System.Linq; +using System.Text; + + +namespace UniJSON +{ + public static class JsonString + { + #region Quote + public static void Escape(String s, IStore w) + { + if (String.IsNullOrEmpty(s)) + { + return; + } + + var it = s.ToCharArray().Cast().GetEnumerator(); + while (it.MoveNext()) + { + switch (it.Current) + { + case '"': + case '\\': + case '/': + // \\ prefix + w.Write('\\'); + w.Write(it.Current); + break; + + case '\b': + w.Write('\\'); + w.Write('b'); + break; + case '\f': + w.Write('\\'); + w.Write('f'); + break; + case '\n': + w.Write('\\'); + w.Write('n'); + break; + case '\r': + w.Write('\\'); + w.Write('r'); + break; + case '\t': + w.Write('\\'); + w.Write('t'); + break; + + default: + w.Write(it.Current); + break; + } + } + } + + public static void Escape(Utf8String s, IStore w) + { + if (s.IsEmpty) + { + return; + } + + var it = s.GetIterator(); + while(it.MoveNext()) + { + var l = it.CurrentByteLength; + if (l == 1) + { + var b = it.Current; + switch (b) + { + case (Byte)'"': + case (Byte)'\\': + case (Byte)'/': + // \\ prefix + w.Write((Byte)'\\'); + w.Write(b); + break; + + case (Byte)'\b': + w.Write((Byte)'\\'); + w.Write((Byte)'b'); + break; + case (Byte)'\f': + w.Write((Byte)'\\'); + w.Write((Byte)'f'); + break; + case (Byte)'\n': + w.Write((Byte)'\\'); + w.Write((Byte)'n'); + break; + case (Byte)'\r': + w.Write((Byte)'\\'); + w.Write((Byte)'r'); + break; + case (Byte)'\t': + w.Write((Byte)'\\'); + w.Write((Byte)'t'); + break; + + default: + w.Write(b); + break; + } + // ascii + } + else if (l == 2) + { + w.Write(it.Current); + w.Write(it.Second); + } + else if (l == 3) + { + w.Write(it.Current); + w.Write(it.Second); + w.Write(it.Third); + } + else if (l == 4) + { + w.Write(it.Current); + w.Write(it.Second); + w.Write(it.Third); + w.Write(it.Fourth); + } + else + { + throw new ParserException("invalid utf8"); + } + } + } + + public static string Escape(String s) + { + var sb = new StringBuilder(); + Escape(s, new StringBuilderStore(sb)); + return sb.ToString(); + } + + public static void Quote(String s, IStore w) + { + w.Write('"'); + Escape(s, w); + w.Write('"'); + } + + public static void Quote(Utf8String s, IStore w) + { + w.Write((Byte)'"'); + Escape(s, w); + w.Write((Byte)'"'); + } + + /// + /// Added " and Escape + /// + /// + /// + public static string Quote(string s) + { + var sb = new StringBuilder(); + Quote(s, new StringBuilderStore(sb)); + return sb.ToString(); + } + + public static Utf8String Quote(Utf8String s) + { + var sb = new BytesStore(s.ByteLength); + Quote(s, sb); + return new Utf8String(sb.Bytes); + } + #endregion + + #region Unquote + public static int Unescape(string src, IStore w) + { + int writeCount = 0; + Action Write = c => + { + if (w != null) + { + w.Write(c); + } + ++writeCount; + }; + + int i = 0; + int length = src.Length - 1; + while (i < length) + { + if (src[i] == '\\') + { + var c = src[i + 1]; + switch (c) + { + case '\\': + case '/': + case '"': + // remove prefix + Write(c); + i += 2; + continue; + + case 'b': + Write('\b'); + i += 2; + continue; + case 'f': + Write('\f'); + i += 2; + continue; + case 'n': + Write('\n'); + i += 2; + continue; + case 'r': + Write('\r'); + i += 2; + continue; + case 't': + Write('\t'); + i += 2; + continue; + } + } + + Write(src[i]); + i += 1; + } + while (i <= length) + { + Write(src[i++]); + } + + return writeCount; + } + + public static int Unescape(Utf8String s, IStore w) + { + int writeCount = 0; + Action Write = c => + { + if (w != null) + { + w.Write(c); + } + ++writeCount; + }; + + var it = s.GetIterator(); + while(it.MoveNext()) + { + var l = it.CurrentByteLength; + if (l == 1) + { + if (it.Current == (Byte)'\\') + { + var c = it.Second; + switch (c) + { + case (Byte)'\\': + case (Byte)'/': + case (Byte)'"': + // remove prefix + Write(c); + it.MoveNext(); + continue; + + case (Byte)'b': + Write((Byte)'\b'); + it.MoveNext(); + continue; + case (Byte)'f': + Write((Byte)'\f'); + it.MoveNext(); + continue; + case (Byte)'n': + Write((Byte)'\n'); + it.MoveNext(); + continue; + case (Byte)'r': + Write((Byte)'\r'); + it.MoveNext(); + continue; + case (Byte)'t': + Write((Byte)'\t'); + it.MoveNext(); + continue; + } + } + + Write(it.Current); + } + else if (l == 2) + { + Write(it.Current); + Write(it.Second); + } + else if (l == 3) + { + Write(it.Current); + Write(it.Second); + Write(it.Third); + } + else if (l == 4) + { + Write(it.Current); + Write(it.Second); + Write(it.Third); + Write(it.Fourth); + } + else + { + throw new ParserException("invalid utf8"); + } + } + + return writeCount; + } + + public static string Unescape(string src) + { + var sb = new StringBuilder(); + Unescape(src, new StringBuilderStore(sb)); + return sb.ToString(); + } + + public static int Unquote(string src, IStore w) + { + return Unescape(src.Substring(1, src.Length - 2), w); + } + + public static int Unquote(Utf8String src, IStore w) + { + return Unescape(src.Subbytes(1, src.ByteLength - 2), w); + } + + public static string Unquote(string src) + { + var count = Unquote(src, null); + if (count == src.Length - 2) + { + return src.Substring(1, src.Length - 2); + } + else + { + var sb = new StringBuilder(count); + Unquote(src, new StringBuilderStore(sb)); + var str = sb.ToString(); + return str; + } + } + + public static Utf8String Unquote(Utf8String src) + { + var count = Unquote(src, null); + if (count == src.ByteLength - 2) + { + return src.Subbytes(1, src.ByteLength - 2); + } + else + { + var sb = new BytesStore(count); + Unquote(src, sb); + return new Utf8String(sb.Bytes); + } + } + #endregion + } +} diff --git a/Scripts/Json/JsonString.cs.meta b/Scripts/Json/JsonString.cs.meta new file mode 100644 index 000000000..46741726b --- /dev/null +++ b/Scripts/Json/JsonString.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 04a331b0f78f87e4d928172d735672d9 +timeCreated: 1495517071 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Json/JsonValue.cs b/Scripts/Json/JsonValue.cs new file mode 100644 index 000000000..176952d4e --- /dev/null +++ b/Scripts/Json/JsonValue.cs @@ -0,0 +1,111 @@ +using System; + + +namespace UniJSON +{ + public struct JsonValue : IListTreeItem, IValue + { + public Utf8String Segment; + public ArraySegment Bytes { get { return Segment.Bytes; } } + + public ValueNodeType ValueType + { + get; + private set; + } + + public int ParentIndex + { + get; + private set; + } + + public JsonValue(Utf8String segment, ValueNodeType valueType, int parentIndex) : this() + { + Segment = segment; + ValueType = valueType; + ParentIndex = parentIndex; + } + + public JsonValue New(ArraySegment bytes, ValueNodeType valueType, int parentIndex) + { + return new JsonValue(new Utf8String(bytes), valueType, parentIndex); + } + + public JsonValue Key(Utf8String key, int parentIndex) + { + return new JsonValue(JsonString.Quote(key), ValueNodeType.String, parentIndex); + } + + public override string ToString() + { + switch (ValueType) + { + case ValueNodeType.Null: + case ValueNodeType.Boolean: + case ValueNodeType.Integer: + case ValueNodeType.Number: + case ValueNodeType.Array: + case ValueNodeType.Object: + case ValueNodeType.String: + case ValueNodeType.NaN: + case ValueNodeType.Infinity: + case ValueNodeType.MinusInfinity: + return Segment.ToString(); + + default: + throw new NotImplementedException(); + } + } + + static Utf8String s_true = Utf8String.From("true"); + static Utf8String s_false = Utf8String.From("false"); + + public Boolean GetBoolean() + { + if (Segment == s_true) + { + return true; + } + else if (Segment == s_false) + { + return false; + } + else + { + throw new DeserializationException("invalid boolean: " + Segment.ToString()); + } + } + + public SByte GetSByte() { return Segment.ToSByte(); } + public Int16 GetInt16() { return Segment.ToInt16(); } + public Int32 GetInt32() { return Segment.ToInt32(); } + public Int64 GetInt64() { return Segment.ToInt64(); } + public Byte GetByte() { return Segment.ToByte(); } + public UInt16 GetUInt16() { return Segment.ToUInt16(); } + public UInt32 GetUInt32() { return Segment.ToUInt32(); } + public UInt64 GetUInt64() { return Segment.ToUInt64(); } + public Single GetSingle() { return Segment.ToSingle(); } + public Double GetDouble() { return Segment.ToDouble(); } + public String GetString() { return JsonString.Unquote(Segment.ToString()); } + public Utf8String GetUtf8String() { return JsonString.Unquote(Segment); } + + public T GetValue() + { + switch (ValueType) + { + case ValueNodeType.Null: return GenericCast.Null(); + case ValueNodeType.Boolean: return GenericCast.Cast(GetBoolean()); + case ValueNodeType.Integer: return GenericCast.Cast(GetInt32()); + case ValueNodeType.Number: + case ValueNodeType.NaN: + case ValueNodeType.Infinity: + case ValueNodeType.MinusInfinity: + return GenericCast.Cast(GetDouble()); + case ValueNodeType.String: return GenericCast.Cast(GetString()); + } + + throw new NotImplementedException(); + } + } +} diff --git a/Scripts/Json/JsonValue.cs.meta b/Scripts/Json/JsonValue.cs.meta new file mode 100644 index 000000000..314b71424 --- /dev/null +++ b/Scripts/Json/JsonValue.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0b59a66ed8e7b1c419d69f7ee07900c1 +timeCreated: 1526178270 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator.meta b/Scripts/JsonSchemaValidator.meta new file mode 100644 index 000000000..817676fed --- /dev/null +++ b/Scripts/JsonSchemaValidator.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bebbecaad7b8e70479f6378faadbccbe +folderAsset: yes +timeCreated: 1531812228 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs b/Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs new file mode 100644 index 000000000..3817ad995 --- /dev/null +++ b/Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; + +namespace UniJSON +{ + public class JsonSchemaValidationContext + { + Stack m_stack = new Stack(); + + public JsonSchemaValidationContext(object o) + { + Push(o.GetType().Name); + } + + public ActionDisposer Push(object o) + { + m_stack.Push(o.ToString()); + return new ActionDisposer(Pop); + } + + public void Pop() + { + m_stack.Pop(); + } + + public bool IsEmpty() + { + return m_stack.Count == 1; // A first element will be remained. + } + + public override string ToString() + { + return string.Join(".", m_stack.ToArray(), 0, m_stack.Count); + } + } + + + public class JsonSchemaValidationException : Exception + { + public Exception Error + { + get; private set; + } + + public JsonSchemaValidationException(JsonSchemaValidationContext context, string msg) : base(string.Format("[{0}] {1}", context, msg)) + { + } + + public JsonSchemaValidationException(JsonSchemaValidationContext context, Exception ex) : base(string.Format("[{0}] {1}", context, ex)) + { + Error = ex; + } + } + + + public interface IJsonSchemaValidator + { + #region JsonSchema + void Merge(IJsonSchemaValidator rhs); + + /// + /// Parse json schema + /// + /// + /// + /// + /// + bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value); + + void ToJsonScheama(IFormatter f); + #endregion + + #region Serializer + /// + /// + /// + /// + /// return null if validate value + JsonSchemaValidationException Validate(JsonSchemaValidationContext context, T value); + + void Serialize(IFormatter f, JsonSchemaValidationContext context, T value); + + void Deserialize(ListTreeNode src, ref U dst) where T : IListTreeItem, IValue; + #endregion + } +} diff --git a/Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs.meta b/Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs.meta new file mode 100644 index 000000000..0470e0b49 --- /dev/null +++ b/Scripts/JsonSchemaValidator/IJsonSchemaValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c35476cdb8e1a4541b2f06b9b11141d0 +timeCreated: 1531812340 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonArrayValidator.cs b/Scripts/JsonSchemaValidator/JsonArrayValidator.cs new file mode 100644 index 000000000..116e61011 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonArrayValidator.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + + +namespace UniJSON +{ + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4 + /// + public class JsonArrayValidator : IJsonSchemaValidator + { + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4.1 + /// + public JsonSchema Items + { + get; set; + } + + // additionalItems + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4.3 + /// + public int? MaxItems + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4.4 + /// + public int? MinItems + { + get; set; + } + + // uniqueItems + + // contains + + public override int GetHashCode() + { + return 5; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonArrayValidator; + if (rhs == null) return false; + + if (Items != rhs.Items) return false; + if (MaxItems != rhs.MaxItems) return false; + if (MinItems != rhs.MinItems) return false; + + return true; + } + + public void Merge(IJsonSchemaValidator rhs) + { + throw new NotImplementedException(); + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + switch (key) + { + case "items": + if (value.IsArray()) + { + throw new NotImplementedException(); + } + else + { + var sub = new JsonSchema(); + sub.Parse(fs, value, "items"); + Items = sub; + } + return true; + + case "additionalItems": + return true; + + case "maxItems": + MaxItems = value.GetInt32(); + return true; + + case "minItems": + MinItems = value.GetInt32(); + return true; + + case "uniqueItems": + return true; + + case "contains": + return true; + } + + return false; + } + + static class GenericCounter + { + delegate int Counter(T value); + + static Counter s_counter; + + public static int Count(T value) + { + if (s_counter == null) + { + var t = typeof(T); + if (t.IsArray) + { + var pi = t.GetProperty("Length"); + var v = Expression.Parameter(t, "value"); + var call = Expression.Property(v, pi); + var compiled = (Func)Expression.Lambda(call, v).Compile(); + s_counter = new Counter(compiled); + } + else if (t.GetIsGenericList()) + { + var pi = t.GetProperty("Count"); + var v = Expression.Parameter(t, "value"); + var call = Expression.Property(v, pi); + var compiled = (Func)Expression.Lambda(call, v).Compile(); + s_counter = new Counter(compiled); + } + else + { + throw new NotImplementedException(); + } + } + return s_counter(value); + } + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext context, T o) + { + if (o == null) + { + return new JsonSchemaValidationException(context, "null"); + } + + var count = GenericCounter.Count(o); + if (count == 0) + { + return new JsonSchemaValidationException(context, "empty"); + } + + if (MaxItems.HasValue && count > MaxItems.Value) + { + return new JsonSchemaValidationException(context, "maxOtems"); + } + + if (MinItems.HasValue && count < MinItems.Value) + { + return new JsonSchemaValidationException(context, "minItems"); + } + + return null; + } + + static void ArraySerializer(IJsonSchemaValidator v, IFormatter f, JsonSchemaValidationContext c, U[] array) + { + f.BeginList(array.Length); + { + //int i = 0; + foreach (var x in array) + { + //using (c.Push(i++)) + { + v.Serialize(f, c, x); + } + } + } + f.EndList(); + } + + static void ListSerializer(IJsonSchemaValidator v, IFormatter f, JsonSchemaValidationContext c, List list) + { + f.BeginList(list.Count); + { + //int i = 0; + foreach (var x in list) + { + //using (c.Push(i++)) + { + v.Serialize(f, c, x); + } + } + } + f.EndList(); + } + + static class GenericSerializer + { + delegate void Serializer(IJsonSchemaValidator v, IFormatter f, JsonSchemaValidationContext c, T o); + + static Serializer s_serializer; + + public static void Serialize(IJsonSchemaValidator v, IFormatter f, JsonSchemaValidationContext c, T o) + { + if (s_serializer == null) + { + var t = typeof(T); + MethodInfo g = null; + if (t.IsArray) + { + var mi = typeof(JsonArrayValidator).GetMethod("ArraySerializer", + BindingFlags.Static | BindingFlags.NonPublic); + g = mi.MakeGenericMethod(t.GetElementType()); + } + else if (t.GetIsGenericList()) + { + // ToDo: IList + var mi = typeof(JsonArrayValidator).GetMethod("ListSerializer", + BindingFlags.Static | BindingFlags.NonPublic); + g = mi.MakeGenericMethod(t.GetGenericArguments()); + } + else + { + throw new NotImplementedException(); + } + var vv = Expression.Parameter(typeof(IJsonSchemaValidator), "v"); + var ff = Expression.Parameter(typeof(IFormatter), "f"); + var cc = Expression.Parameter(typeof(JsonSchemaValidationContext), "c"); + var oo = Expression.Parameter(typeof(T), "o"); + var call = Expression.Call(g, vv, ff, cc, oo); + var compiled = (Action)Expression.Lambda(call, vv, ff, cc, oo).Compile(); + s_serializer = new Serializer(compiled); + } + s_serializer(v, f, c, o); + } + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T o) + { + GenericSerializer.Serialize(Items.Validator, f, c, o); + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("array"); + + if (Items != null) + { + f.Key("items"); + Items.ToJson(f); + } + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + src.Deserialize(ref dst); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonArrayValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonArrayValidator.cs.meta new file mode 100644 index 000000000..0c5ed09b5 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonArrayValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6144a646f2f535641885a006024771a4 +timeCreated: 1531812663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonBoolValidator.cs b/Scripts/JsonSchemaValidator/JsonBoolValidator.cs new file mode 100644 index 000000000..a9afa9086 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonBoolValidator.cs @@ -0,0 +1,51 @@ +using System; + + +namespace UniJSON +{ + public class JsonBoolValidator : IJsonSchemaValidator + { + public override int GetHashCode() + { + return 1; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonBoolValidator; + if (rhs == null) return false; + return true; + } + + public void Merge(IJsonSchemaValidator obj) + { + throw new NotImplementedException(); + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + return false; + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("boolean"); + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T value) + { + return null; + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T value) + { + f.Serialize(value); + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + dst = GenericCast.Cast(src.GetBoolean()); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonBoolValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonBoolValidator.cs.meta new file mode 100644 index 000000000..6604e10ce --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonBoolValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2a6454bbd9b910d499702d2ba8270ea0 +timeCreated: 1531812394 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs b/Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs new file mode 100644 index 000000000..c180aba69 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs @@ -0,0 +1,290 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +namespace UniJSON +{ + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5 + /// + public class JsonDictionaryValidator : IJsonSchemaValidator + { + public JsonDictionaryValidator() + { + AdditionalProperties = JsonSchema.FromType(); + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.1 + /// + public int MaxProperties + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.2 + /// + public int MinProperties + { + get; set; + } + + List m_required = new List(); + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.3 + /// + public List Required + { + get { return m_required; } + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.5 + /// + public string PatternProperties + { + get; private set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.6 + /// + public JsonSchema AdditionalProperties + { + get; set; + } + + Dictionary m_depndencies; + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.7 + /// + public Dictionary Dependencies + { + get + { + if (m_depndencies == null) + { + m_depndencies = new Dictionary(); + } + return m_depndencies; + } + } + + public override int GetHashCode() + { + return 6; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonObjectValidator; + if (rhs == null) + { + return false; + } + + if (Required.Count != rhs.Required.Count) + { + return false; + } + if (!Required.OrderBy(x => x).SequenceEqual(rhs.Required.OrderBy(x => x))) + { + return false; + } + + if (Dependencies.Count != rhs.Dependencies.Count) + { + return false; + } + foreach (var kv in Dependencies) + { + if (!kv.Value.OrderBy(x => x).SequenceEqual(rhs.Dependencies[kv.Key].OrderBy(x => x))) + { + return false; + } + } + + if (AdditionalProperties == null + && rhs.AdditionalProperties == null) + { + // ok + } + else if (AdditionalProperties == null) + { + return false; + } + else if (rhs.AdditionalProperties == null) + { + return false; + } + else + { + if (!AdditionalProperties.Equals(rhs.AdditionalProperties)) + { + return false; + } + } + + return true; + } + + public void Merge(IJsonSchemaValidator obj) + { + var rhs = obj as JsonObjectValidator; + if (rhs == null) + { + throw new ArgumentException(); + } + + foreach (var x in rhs.Required) + { + this.Required.Add(x); + } + + if (rhs.AdditionalProperties != null) + { + if (AdditionalProperties != null) + { + throw new NotImplementedException(); + } + AdditionalProperties = rhs.AdditionalProperties; + } + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + switch (key) + { + case "maxProperties": + MaxProperties = value.GetInt32(); + return true; + + case "minProperties": + MinProperties = value.GetInt32(); + return true; + + case "required": + { + foreach (var req in value.ArrayItems()) + { + m_required.Add(req.GetString()); + } + } + return true; + + case "patternProperties": + PatternProperties = value.GetString(); + return true; + + case "additionalProperties": + { + var sub = new JsonSchema(); + sub.Parse(fs, value, "additionalProperties"); + AdditionalProperties = sub; + } + return true; + + case "dependencies": + { + foreach (var kv in value.ObjectItems()) + { + Dependencies.Add(kv.Key.GetString(), kv.Value.ArrayItems().Select(x => x.GetString()).ToArray()); + } + } + return true; + + case "propertyNames": + return true; + } + + return false; + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("object"); + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, S o) + { + if (o == null) + { + return new JsonSchemaValidationException(c, "null"); + } + + var d = o as IDictionary; + if (d == null) + { + return new JsonSchemaValidationException(c, "not dictionary"); + } + + if (Required != null) + { + foreach (var x in Required) + { + using (c.Push(x)) + { + // ToDo + } + } + } + + if (AdditionalProperties != null) + { + foreach (var kv in d) + { + using (c.Push(kv.Key)) + { + var result = AdditionalProperties.Validator.Validate(c, kv.Value); + if (result != null) + { + return result; + } + } + } + } + + return null; + } + + Dictionary m_validValueMap = new Dictionary(); + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, S o) + { + // validate properties + m_validValueMap.Clear(); + + var dict = o as Dictionary; + f.BeginMap(dict.Count); + { + foreach (var kv in dict) + { + // key + f.Key(kv.Key); + + // value + //using (c.Push(kv.Key)) + { + AdditionalProperties.Validator.Serialize(f, c, kv.Value); + } + } + } + f.EndMap(); + } + + public void Deserialize(ListTreeNode src, ref V dst) + where U : IListTreeItem, IValue + { + throw new NotImplementedException(); + } + } + + public static class JsonDictionaryValidator + { + public static JsonDictionaryValidator Create() + { + return new JsonDictionaryValidator(); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs.meta new file mode 100644 index 000000000..65d5fbc05 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonDictionaryValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ccee0323c35d40d498d45b207124fe7e +timeCreated: 1531812708 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonEnumValidator.cs b/Scripts/JsonSchemaValidator/JsonEnumValidator.cs new file mode 100644 index 000000000..fbcaa5f73 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonEnumValidator.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace UniJSON +{ + public static class JsonEnumValidator + { + public static IJsonSchemaValidator Create(ListTreeNode value) + { + foreach (var x in value.ArrayItems()) + { + if (x.IsInteger() || x.IsFloat()) + { + return JsonIntEnumValidator.Create(value.ArrayItems() + .Where(y => y.IsInteger() || y.IsFloat()) + .Select(y => y.GetInt32()) + ); + } + else if (x.IsString()) + { + + return JsonStringEnumValidator.Create(value.ArrayItems() + .Where(y => y.IsString()) + .Select(y => y.GetString()) + , EnumSerializationType.AsString + ); + } + else + { + } + } + + throw new NotImplementedException(); + } + + public static IJsonSchemaValidator Create(IEnumerable composition, EnumSerializationType type) + { + foreach (var x in composition) + { + if (x.Validator is JsonStringEnumValidator) + { + return JsonStringEnumValidator.Create(composition + .Select(y => y.Validator as JsonStringEnumValidator) + .Where(y => y != null) + .SelectMany(y => y.Values), + type + ); + } + if (x.Validator is JsonIntEnumValidator) + { + return JsonIntEnumValidator.Create(composition + .Select(y => y.Validator as JsonIntEnumValidator) + .Where(y => y != null) + .SelectMany(y => y.Values) + ); + } + } + + throw new NotImplementedException(); + } + + static IEnumerable GetStringValues(Type t, object[] excludes, Func filter) + { + foreach (var x in Enum.GetValues(t)) + { + if (excludes == null || !excludes.Contains(x)) + { + yield return filter(x.ToString()); + } + } + } + + static IEnumerable GetIntValues(Type t, object[] excludes) + { + foreach (var x in Enum.GetValues(t)) + { + if (excludes == null || !excludes.Contains(x)) + { + yield return (int)x; + } + } + } + + public static IJsonSchemaValidator Create(Type t, EnumSerializationType serializationType, object[] excludes) + { + switch (serializationType) + { + case EnumSerializationType.AsInt: + return JsonIntEnumValidator.Create(GetIntValues(t, excludes)); + + case EnumSerializationType.AsString: + return JsonStringEnumValidator.Create(GetStringValues(t, excludes, x => x), serializationType); + + case EnumSerializationType.AsLowerString: + return JsonStringEnumValidator.Create(GetStringValues(t, excludes, x => x.ToLower()), serializationType); + + case EnumSerializationType.AsUpperString: + return JsonStringEnumValidator.Create(GetStringValues(t, excludes, x => x.ToUpper()), serializationType); + + default: + throw new NotImplementedException(); + } + } + + public static IJsonSchemaValidator Create(object[] values, EnumSerializationType type) + { + foreach (var x in values) + { + if (x is string) + { + return JsonStringEnumValidator.Create(values.Select(y => (string)y), type); + } + if (x is int) + { + return JsonIntEnumValidator.Create(values.Select(y => (int)y)); + } + } + + throw new NotImplementedException(); + } + } + + public class JsonStringEnumValidator : IJsonSchemaValidator + { + EnumSerializationType SerializationType; + + public String[] Values + { + get; set; + } + + JsonStringEnumValidator(IEnumerable values, EnumSerializationType type) + { + SerializationType = type; + switch (SerializationType) + { + case EnumSerializationType.AsString: + Values = values.ToArray(); + break; + + case EnumSerializationType.AsLowerString: + Values = values.Select(x => x.ToLower()).ToArray(); + break; + + case EnumSerializationType.AsUpperString: + Values = values.Select(x => x.ToUpper()).ToArray(); + break; + + case EnumSerializationType.AsInt: + throw new ArgumentException("JsonStringEnumValidator not allow AsInt"); + + default: + throw new NotImplementedException(""); + } + } + + public static JsonStringEnumValidator Create(IEnumerable values, EnumSerializationType type) + { + return new JsonStringEnumValidator(values, type); + } + + public override int GetHashCode() + { + return 7; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonStringEnumValidator; + if (rhs == null) return false; + + if (Values.Length != rhs.Values.Length) return false; + + var l = Values.OrderBy(x => x).GetEnumerator(); + var r = rhs.Values.OrderBy(x => x).GetEnumerator(); + while (l.MoveNext() && r.MoveNext()) + { + if (l.Current != r.Current) + { + return false; + } + } + return true; + } + + public void Merge(IJsonSchemaValidator obj) + { + throw new NotImplementedException(); + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + throw new NotImplementedException(); + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("string"); + f.Key("enum"); + f.BeginList(Values.Length); + foreach (var x in Values) + { + f.Value(x); + } + f.EndList(); + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) + { + if (o == null) + { + return new JsonSchemaValidationException(c, "null"); + } + + var t = o.GetType(); + string value = null; + if (t.IsEnum) + { + value = Enum.GetName(t, o); + } + else + { + value = GenericCast.Cast(o); + } + + if (SerializationType == EnumSerializationType.AsLowerString) + { + value = value.ToLower(); + } + else if (SerializationType == EnumSerializationType.AsUpperString) + { + value = value.ToUpper(); + } + + if (Values.Contains(value)) + { + return null; + } + else + { + return new JsonSchemaValidationException(c, string.Format("{0} is not valid enum", o)); + } + } + + public static class GenericSerializer + { + delegate void Serializer(JsonStringEnumValidator v, + IFormatter f, JsonSchemaValidationContext c, T o); + + static Serializer s_serializer; + + public static void Serialize(JsonStringEnumValidator validator, + IFormatter f, JsonSchemaValidationContext c, T o) + { + if (s_serializer == null) + { + var t = typeof(T); + if (t.IsEnum) + { + s_serializer = (vv, ff, cc, oo) => + { + var value = Enum.GetName(t, oo); + if (vv.SerializationType == EnumSerializationType.AsLowerString) + { + value = value.ToLower(); + } + else if (vv.SerializationType == EnumSerializationType.AsUpperString) + { + value = value.ToUpper(); + } + ff.Value(value); + }; + } + else if (t == typeof(string)) + { + s_serializer = (vv, ff, cc, oo) => + { + var value = GenericCast.Cast(oo); + if (vv.SerializationType == EnumSerializationType.AsLowerString) + { + value = value.ToLower(); + } + else if (vv.SerializationType == EnumSerializationType.AsUpperString) + { + value = value.ToUpper(); + } + ff.Value(value); + }; + } + else + { + throw new NotImplementedException(); + } + } + s_serializer(validator, f, c, o); + } + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T o) + { + GenericSerializer.Serialize(this, f, c, o); + } + + static class GenericDeserializer + where T: IListTreeItem, IValue + { + delegate U Deserializer(ListTreeNode src); + static Deserializer s_d; + public static void Deserialize(ListTreeNode src, ref U t) + { + if (s_d == null) + { + if (typeof(U).IsEnum) + { + // enum from string + var mi = typeof(Enum).GetMethods(BindingFlags.Static | BindingFlags.Public).First( + x => x.Name == "Parse" && x.GetParameters().Length == 3 + ); + var type = Expression.Constant(typeof(U)); + var value = Expression.Parameter(typeof(string), "value"); + var ic = Expression.Constant(true); + var call = Expression.Call(mi, type, value, ic); + var lambda = Expression.Lambda(call, value); + var func = (Func)lambda.Compile(); + s_d = x => GenericCast.Cast(func(x.GetString())); + } + else + { + s_d = x => GenericCast.Cast(x.GetString()); + } + } + t = s_d(src); + } + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + GenericDeserializer.Deserialize(src, ref dst); + } + } + + public class JsonIntEnumValidator : IJsonSchemaValidator + { + public int[] Values + { + get; set; + } + + public static JsonIntEnumValidator Create(IEnumerable values) + { + return new JsonIntEnumValidator + { + Values = values.ToArray() + }; + } + + public override int GetHashCode() + { + return 7; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonIntEnumValidator; + if (rhs == null) return false; + + if (Values.Length != rhs.Values.Length) return false; + + var l = Values.OrderBy(x => x).GetEnumerator(); + var r = rhs.Values.OrderBy(x => x).GetEnumerator(); + while (l.MoveNext() && r.MoveNext()) + { + if (l.Current != r.Current) + { + return false; + } + } + return true; + } + + public void Merge(IJsonSchemaValidator obj) + { + throw new NotImplementedException(); + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + throw new NotImplementedException(); + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("integer"); + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) + { + if (Values.Contains(GenericCast.Cast(o))) + { + return null; + } + else + { + return new JsonSchemaValidationException(c, string.Format("{0} is not valid enum", o)); + } + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T o) + { + f.Serialize(GenericCast.Cast(o)); + } + + static class GenericDeserializer + where T : IListTreeItem, IValue + { + delegate U Deserializer(ListTreeNode src); + + static Deserializer s_d; + + public static void Deserialize(ListTreeNode src, ref U dst) + { + if (s_d == null) + { + // enum from int + var value = Expression.Parameter(typeof(int), "value"); + var cast = Expression.Convert(value, typeof(U)); + var lambda = Expression.Lambda(cast, value); + var func = (Func)lambda.Compile(); + s_d = s => func(s.GetInt32()); + } + dst = s_d(src); + } + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + GenericDeserializer.Deserialize(src, ref dst); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonEnumValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonEnumValidator.cs.meta new file mode 100644 index 000000000..0fd90809b --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonEnumValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f503fff7ab8dcf74abc9dd8073aa9062 +timeCreated: 1531812758 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonNumberValidator.cs b/Scripts/JsonSchemaValidator/JsonNumberValidator.cs new file mode 100644 index 000000000..3dafbc253 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonNumberValidator.cs @@ -0,0 +1,430 @@ +using System; + + +namespace UniJSON +{ + /// + /// http://json-schema.org/latest/json-schema-validation.html#numeric + /// + public class JsonIntValidator : IJsonSchemaValidator + { + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.1 + /// + public int? MultipleOf + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.2 + /// + public int? Maximum + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.3 + /// + public bool ExclusiveMaximum + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.4 + /// + public int? Minimum + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.5 + /// + public bool ExclusiveMinimum + { + get; set; + } + + public override int GetHashCode() + { + return 2; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonIntValidator; + if (rhs == null) return false; + + if (MultipleOf != rhs.MultipleOf) + { + Console.WriteLine("MultipleOf"); + return false; + } + if (Maximum != rhs.Maximum) + { + Console.WriteLine("Maximum"); + return false; + } + + if (ExclusiveMaximum != rhs.ExclusiveMaximum) + { + Console.WriteLine("ExclusiveMaximum"); + return false; + } + + if (Minimum != rhs.Minimum) + { + Console.WriteLine("Minimum"); + return false; + } + + if (ExclusiveMinimum != rhs.ExclusiveMinimum) + { + Console.WriteLine("ExclusiveMinimum"); + return false; + } + + return true; + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + switch (key) + { + case "multipleOf": + MultipleOf = value.GetInt32(); + return true; + + case "maximum": + Maximum = value.GetInt32(); + return true; + + case "exclusiveMaximum": + ExclusiveMaximum = value.GetBoolean(); + return true; + + case "minimum": + Minimum = value.GetInt32(); + return true; + + case "exclusiveMinimum": + ExclusiveMinimum = value.GetBoolean(); + return true; + } + + return false; + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("integer"); + if (Minimum.HasValue) + { + f.Key("minimum"); f.Value(Minimum.Value); + } + if (Maximum.HasValue) + { + f.Key("maximum"); f.Value(Maximum.Value); + } + } + + public void Merge(IJsonSchemaValidator obj) + { + var rhs = obj as JsonIntValidator; + if (rhs == null) + { + throw new ArgumentException(); + } + + MultipleOf = rhs.MultipleOf; + Maximum = rhs.Maximum; + ExclusiveMaximum = rhs.ExclusiveMaximum; + Minimum = rhs.Minimum; + ExclusiveMinimum = rhs.ExclusiveMinimum; + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) + { + try + { + var value = GenericCast.Cast(o); + + if (Minimum.HasValue) + { + if (ExclusiveMinimum) + { + if (value > Minimum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("minimum: ! {0}>{1}", value, Minimum.Value)); + } + } + else + { + if (value >= Minimum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("minimum: ! {0}>={1}", value, Minimum.Value)); + } + } + } + + if (Maximum.HasValue) + { + if (ExclusiveMaximum) + { + if (value < Maximum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("maximum: ! {0}<{1}", value, Maximum.Value)); + } + } + else + { + if (value <= Maximum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("maximum: ! {0}<={1}", value, Maximum.Value)); + } + } + } + + if (MultipleOf.HasValue && value % MultipleOf.Value != 0) + { + return new JsonSchemaValidationException(c, string.Format("multipleOf: {0}%{1}", value, MultipleOf.Value)); + } + + return null; + } + catch (Exception ex) + { + return new JsonSchemaValidationException(c, ex); + } + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T o) + { + f.Serialize(GenericCast.Cast(o)); + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + dst = GenericCast.Cast(src.GetInt32()); + } + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#numeric + /// + public class JsonNumberValidator : IJsonSchemaValidator + { + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.1 + /// + public double? MultipleOf + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.2 + /// + public double? Maximum + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.3 + /// + public bool ExclusiveMaximum + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.4 + /// + public double? Minimum + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2.5 + /// + public bool ExclusiveMinimum + { + get; set; + } + + public override int GetHashCode() + { + return 3; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonNumberValidator; + if (rhs == null) return false; + + if (MultipleOf != rhs.MultipleOf) return false; + if (Maximum != rhs.Maximum) return false; + if (ExclusiveMaximum != rhs.ExclusiveMaximum) return false; + if (Minimum != rhs.Minimum) return false; + if (ExclusiveMinimum != rhs.ExclusiveMinimum) return false; + + return true; + } + + public void Merge(IJsonSchemaValidator rhs) + { + throw new NotImplementedException(); + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + switch (key) + { + case "multipleOf": + MultipleOf = value.GetDouble(); + return true; + + case "maximum": + Maximum = value.GetDouble(); + return true; + + case "exclusiveMaximum": + ExclusiveMaximum = value.GetBoolean(); + return true; + + case "minimum": + Minimum = value.GetDouble(); + return true; + + case "exclusiveMinimum": + ExclusiveMinimum = value.GetBoolean(); + return true; + } + + return false; + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("number"); + if (Minimum.HasValue) + { + f.Key("minimum"); f.Value(Minimum.Value); + } + if (Maximum.HasValue) + { + f.Key("maximum"); f.Value(Maximum.Value); + } + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) + { + try + { + var value = Convert.ToDouble(o); + + if (Minimum.HasValue) + { + if (ExclusiveMinimum) + { + if (value > Minimum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("minimum: ! {0}>{1}", value, Minimum.Value)); + } + } + else + { + if (value >= Minimum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("minimum: ! {0}>={1}", value, Minimum.Value)); + } + } + } + + if (Maximum.HasValue) + { + if (ExclusiveMaximum) + { + if (value < Maximum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("maximum: ! {0}<{1}", value, Maximum.Value)); + } + } + else + { + if (value <= Maximum.Value) + { + // ok + } + else + { + return new JsonSchemaValidationException(c, string.Format("maximum: ! {0}<={1}", value, Maximum.Value)); + } + } + } + + /* + if (MultipleOf.HasValue && value % MultipleOf.Value != 0) + { + return new JsonSchemaValidationException(c, string.Format("multipleOf: {0}%{1}", value, MultipleOf.Value)); + } + */ + if (MultipleOf.HasValue) + { + throw new NotImplementedException(); + } + + return null; + } + catch (Exception ex) + { + return new JsonSchemaValidationException(c, ex); + } + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T o) + { + f.Serialize(o); + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + dst = GenericCast.Cast(src.GetDouble()); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonNumberValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonNumberValidator.cs.meta new file mode 100644 index 000000000..6651eeb4b --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonNumberValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fb1d83ccd68b93c47821000b53471eae +timeCreated: 1531812526 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonObjectValidator.cs b/Scripts/JsonSchemaValidator/JsonObjectValidator.cs new file mode 100644 index 000000000..256e84a4a --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonObjectValidator.cs @@ -0,0 +1,605 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + + +namespace UniJSON +{ + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5 + /// + public class JsonObjectValidator : IJsonSchemaValidator + { + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.1 + /// + public int MaxProperties + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.2 + /// + public int MinProperties + { + get; set; + } + + List m_required = new List(); + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.3 + /// + public List Required + { + get { return m_required; } + } + + Dictionary m_props; + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.4 + /// + public Dictionary Properties + { + get + { + if (m_props == null) + { + m_props = new Dictionary(); + } + return m_props; + } + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.5 + /// + public string PatternProperties + { + get; private set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.6 + /// + public JsonSchema AdditionalProperties + { + get; set; + } + + Dictionary m_depndencies; + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.7 + /// + public Dictionary Dependencies + { + get + { + if (m_depndencies == null) + { + m_depndencies = new Dictionary(); + } + return m_depndencies; + } + } + + public void AddProperty(IFileSystemAccessor fs, string key, ListTreeNode value) + { + var sub = new JsonSchema(); + sub.Parse(fs, value, key); + + if (Properties.ContainsKey(key)) + { + if (sub.Validator != null) + { + Properties[key].Validator.Merge(sub.Validator); + } + } + else + { + Properties.Add(key, sub); + } + } + + public override int GetHashCode() + { + return 6; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonObjectValidator; + if (rhs == null) + { + return false; + } + + if (Properties.Count != rhs.Properties.Count) + { + return false; + } + foreach (var pair in Properties) + { + JsonSchema value; + if (rhs.Properties.TryGetValue(pair.Key, out value)) + { +#if true + if (!value.Equals(pair.Value)) + { + Console.WriteLine(string.Format("{0} is not equals", pair.Key)); + var l = pair.Value.Validator; + var r = value.Validator; + return false; + } +#else + // key name match + return true; +#endif + } + else + { + return false; + } + } + + if (Required.Count != rhs.Required.Count) + { + return false; + } + if (!Required.OrderBy(x => x).SequenceEqual(rhs.Required.OrderBy(x => x))) + { + return false; + } + + if (Dependencies.Count != rhs.Dependencies.Count) + { + return false; + } + foreach (var kv in Dependencies) + { + if (!kv.Value.OrderBy(x => x).SequenceEqual(rhs.Dependencies[kv.Key].OrderBy(x => x))) + { + return false; + } + } + + if (AdditionalProperties == null + && rhs.AdditionalProperties == null) + { + // ok + } + else if (AdditionalProperties == null) + { + return false; + } + else if (rhs.AdditionalProperties == null) + { + return false; + } + else + { + if (!AdditionalProperties.Equals(rhs.AdditionalProperties)) + { + return false; + } + } + + return true; + } + + public void Merge(IJsonSchemaValidator obj) + { + var rhs = obj as JsonObjectValidator; + if (rhs == null) + { + throw new ArgumentException(); + } + + foreach (var x in rhs.Properties) + { + if (this.Properties.ContainsKey(x.Key)) + { + this.Properties[x.Key] = x.Value; + } + else + { + this.Properties.Add(x.Key, x.Value); + } + } + + foreach (var x in rhs.Required) + { + this.Required.Add(x); + } + + if (rhs.AdditionalProperties != null) + { + if (AdditionalProperties != null) + { + throw new NotImplementedException(); + } + AdditionalProperties = rhs.AdditionalProperties; + } + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + switch (key) + { + case "maxProperties": + MaxProperties = value.GetInt32(); + return true; + + case "minProperties": + MinProperties = value.GetInt32(); + return true; + + case "required": + { + foreach (var req in value.ArrayItems()) + { + m_required.Add(req.GetString()); + } + } + return true; + + case "properties": + { + foreach (var prop in value.ObjectItems()) + { + AddProperty(fs, prop.Key.GetString(), prop.Value); + } + } + return true; + + case "patternProperties": + PatternProperties = value.GetString(); + return true; + + case "additionalProperties": + { + var sub = new JsonSchema(); + sub.Parse(fs, value, "additionalProperties"); + AdditionalProperties = sub; + } + return true; + + case "dependencies": + { + foreach (var kv in value.ObjectItems()) + { + Dependencies.Add(kv.Key.GetString(), kv.Value.ArrayItems().Select(x => x.GetString()).ToArray()); + } + } + return true; + + case "propertyNames": + return true; + } + + return false; + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("object"); + if (Properties.Count > 0) + { + f.Key("properties"); + f.BeginMap(Properties.Count); + foreach (var kv in Properties) + { + f.Key(kv.Key); + kv.Value.ToJson(f); + } + f.EndMap(); + } + } + + public static class GenericValidator + { + class ObjectValidator + { + delegate JsonSchemaValidationException FieldValidator(IJsonSchemaValidator v, + JsonSchemaValidationContext c, T o); + + Dictionary m_validators = new Dictionary(); + + static FieldValidator CreteFieldValidator(Func getter, string name) + { + return (v, c, o) => + { + using (c.Push(name)) + { + return v.Validate(c, getter(o)); + } + }; + } + + public ObjectValidator() + { + var mi = typeof(ObjectValidator).GetMethod("CreteFieldValidator", + BindingFlags.Static|BindingFlags.NonPublic); + + var t = typeof(T); + foreach(var fi in t.GetFields( + BindingFlags.Instance|BindingFlags.Public)) + { + var value = Expression.Parameter(typeof(T), "value"); + var fieldValue = Expression.Field(value, fi); + var compileld = Expression.Lambda(fieldValue, value).Compile(); + + var getter = Expression.Constant(compileld); + var name = Expression.Constant(fi.Name); + var g = mi.MakeGenericMethod(fi.FieldType); + var call = Expression.Call(g, getter, name); + var lambda = (Func)Expression.Lambda(call).Compile(); + + m_validators.Add(fi.Name, lambda()); + } + } + + public JsonSchemaValidationException Validate(List required, Dictionary properties, + JsonSchemaValidationContext c, T o) + { + foreach (var x in required) + { + JsonSchema s; + if(properties.TryGetValue(x, out s)) + { + FieldValidator fv; + if (m_validators.TryGetValue(x, out fv)) + { + var ex = fv(s.Validator, c, o); + if (ex != null) + { + return ex; + } + } + } + } + return null; + } + } + + static ObjectValidator s_validator; + + public static JsonSchemaValidationException Validate(List required, + Dictionary properties, + JsonSchemaValidationContext c, T o) + { + if (s_validator == null) + { + s_validator = new ObjectValidator(); + } + return s_validator.Validate(required, properties, c, o); + } + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) + { + if (o == null) + { + return new JsonSchemaValidationException(c, "null"); + } + + if (Properties.Count < MinProperties) + { + return new JsonSchemaValidationException(c, "no properties"); + } + + if (Required != null) + { + var ex = GenericValidator.Validate(Required, Properties, c, o); + if (ex != null) + { + return ex; + } + } + + return null; + } + + static class GenericSerializer + { + class Serializer + { + delegate void FieldSerializer(JsonObjectValidator v, IFormatter f, JsonSchemaValidationContext c, T src); + + List m_fieldSerializers = new List(); + + static FieldSerializer CreateSerializer(FieldInfo fi) + { + var src = Expression.Parameter(typeof(T), "src"); + var getter = Expression.Field(src, fi); + var compiled = (Func)Expression.Lambda(getter, src).Compile(); + var name = fi.Name; + return (v, f, c, s) => + { + //c.Push(name); + + var validator = v.Properties[name].Validator; + + var value = compiled(s); + + // validate + if (validator.Validate(c, value) != null) + { + return; + } + + /* + // depencencies + string[] dependencies; + if (validator.Dependencies.TryGetValue(name, out dependencies)) + { + // check dependencies + bool hasDependencies = true; + foreach (var x in dependencies) + { + if (!map.ContainsKey(x)) + { + hasDependencies = false; + break; + } + } + if (!hasDependencies) + { + continue; + } + } + */ + + f.Key(name); + validator.Serialize(f, c, value); + //f.Serialize(value); + + //c.Pop(); + }; + } + + public void AddField(FieldInfo fi) + { + var mi = typeof(Serializer).GetMethod("CreateSerializer", + BindingFlags.Static | BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(fi.FieldType); + var f = Expression.Constant(fi); + var call = Expression.Call(g, f); + var compiled = (Func)Expression.Lambda(call).Compile(); + m_fieldSerializers.Add(compiled()); + } + + public void Serialize(JsonObjectValidator v, IFormatter f, JsonSchemaValidationContext c, T value) + { + f.BeginMap(m_fieldSerializers.Count); + foreach (var s in m_fieldSerializers) + { + s(v, f, c, value); + } + f.EndMap(); + } + } + + static Serializer s_serializer; + + public static void Serialize(JsonObjectValidator validator, + IFormatter f, JsonSchemaValidationContext c, T value) + { + if (s_serializer == null) + { + var t = typeof(T); + if (t == typeof(object)) + { + throw new ArgumentException("object cannot serialize"); + } + var serializer = new Serializer(); + var fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public); + foreach (var fi in fields) + { + serializer.AddField(fi); + } + s_serializer = serializer; + } + s_serializer.Serialize(validator, f, c, value); + } + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T value) + { + GenericSerializer.Serialize(this, f, c, value); + } + + static class GenericDeserializer + where S : IListTreeItem, IValue + { + delegate T Deserializer(ListTreeNode src); + + static Deserializer s_d; + + delegate void FieldSetter(ListTreeNode s, object o); + static FieldSetter GetFieldDeserializer(FieldInfo fi) + { + return (s, o) => + { + var u = default(U); + s.Deserialize(ref u); + fi.SetValue(o, u); + }; + } + + static U DeserializeField(JsonSchema prop, ListTreeNode s) + { + var u = default(U); + prop.Validator.Deserialize(s, ref u); + return u; + } + + public static void Deserialize(ListTreeNode src, ref T dst, Dictionary props) + { + if (s_d == null) + { + var target = typeof(T); + + var fields = target.GetFields(BindingFlags.Instance | BindingFlags.Public); + var fieldDeserializers = fields.ToDictionary(x => Utf8String.From(x.Name), x => + { + /* + var mi = typeof(GenericDeserializer).GetMethod("GetFieldDeserializer", + BindingFlags.Static | BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(x.FieldType); + return (FieldSetter)g.Invoke(null, new object[] { x }); + */ + JsonSchema prop; + if (!props.TryGetValue(x.Name, out prop)) + { + return null; + } + + var mi = typeof(GenericDeserializer).GetMethod("DeserializeField", + BindingFlags.Static | BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(x.FieldType); + + return (FieldSetter)((s, o) => + { + var f = g.Invoke(null, new object[] { prop, s }); + x.SetValue(o, f); + }); + }); + + s_d = (ListTreeNode s) => + { + if (!s.IsMap()) + { + throw new ArgumentException(s.Value.ValueType.ToString()); + } + + // boxing + var t = (object)Activator.CreateInstance(); + foreach (var kv in s.ObjectItems()) + { + FieldSetter setter; + if (fieldDeserializers.TryGetValue(kv.Key.GetUtf8String(), out setter)) + { + if (setter != null) + { + setter(kv.Value, t); + } + } + } + return (T)t; + }; + + } + dst = s_d(src); + } + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T : IListTreeItem, IValue + { + GenericDeserializer.Deserialize(src, ref dst, Properties); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonObjectValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonObjectValidator.cs.meta new file mode 100644 index 000000000..669075111 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonObjectValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1bdf39f36f58f584daee6d67f7ab446f +timeCreated: 1531812708 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonSchemaValidator.cs b/Scripts/JsonSchemaValidator/JsonSchemaValidator.cs new file mode 100644 index 000000000..a6087a119 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonSchemaValidator.cs @@ -0,0 +1,33 @@ +using System; +using System.Linq; +using System.Collections.Generic; + + +namespace UniJSON +{ + [Flags] + public enum PropertyExportFlags + { + None, + PublicFields = 1, + PublicProperties = 2, + + Default = PublicFields | PublicProperties, + } + + public enum CompositionType + { + Unknown, + + AllOf, + AnyOf, + OneOf, + } + + + + + + + +} diff --git a/Scripts/JsonSchemaValidator/JsonSchemaValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonSchemaValidator.cs.meta new file mode 100644 index 000000000..38043343d --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonSchemaValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9ff35fccc1467f341b052622fedcb3ca +timeCreated: 1531557083 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs b/Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs new file mode 100644 index 000000000..f9d9c30c1 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +#if UNIJSON_PROFILING +#else +using UnityEngine; +#endif + + +namespace UniJSON +{ + public static class JsonSchemaValidatorFactory + { + struct JsonSchemaItem + { + public string Key; + public JsonSchema Schema; + public bool Required; + public string[] Dependencies; + } + + static IEnumerable GetProperties(Type t, PropertyExportFlags exportFlags) + { + // fields + foreach (var fi in t.GetFields()) + { + var a = fi.GetCustomAttributes(typeof(JsonSchemaAttribute), true).FirstOrDefault() as JsonSchemaAttribute; + if (a == null) + { + a = fi.FieldType.GetCustomAttributes(typeof(JsonSchemaAttribute), true).FirstOrDefault() as JsonSchemaAttribute; + if (a == null) + { + // default + if (!fi.IsStatic && fi.IsPublic) + { + // only public instance field + a = new JsonSchemaAttribute(); + } + } + } + + // for array item + var ia = fi.GetCustomAttributes(typeof(ItemJsonSchemaAttribute), true).FirstOrDefault() as ItemJsonSchemaAttribute; + + if (a == null) + { + //int x = 0; + } + else + { + yield return new JsonSchemaItem + { + Key = fi.Name, + Schema = JsonSchema.FromType(fi.FieldType, a, ia), + Required = a.Required, + Dependencies = a.Dependencies, + }; + } + } + + // properties + foreach (var pi in t.GetProperties()) + { + var a = pi.GetCustomAttributes(typeof(JsonSchemaAttribute), true).FirstOrDefault() as JsonSchemaAttribute; + + // for array item + var ia = pi.GetCustomAttributes(typeof(ItemJsonSchemaAttribute), true).FirstOrDefault() as ItemJsonSchemaAttribute; + + if (a != null) + { + yield return new JsonSchemaItem + { + Key = pi.Name, + Schema = JsonSchema.FromType(pi.PropertyType, a, ia), + Required = a.Required, + Dependencies = a.Dependencies, + }; + } + } + } + + public static IJsonSchemaValidator Create(ValueNodeType valueType, + Type t = null, + BaseJsonSchemaAttribute a = null, + ItemJsonSchemaAttribute ia = null) + { + switch (valueType) + { + case ValueNodeType.Integer: + { + var v = new JsonIntValidator(); + if (a != null) + { + if (!double.IsNaN(a.Minimum)) + { + v.Minimum = (int)a.Minimum; + } + if (a.ExclusiveMinimum) + { + v.ExclusiveMinimum = a.ExclusiveMinimum; + } + if (!double.IsNaN(a.Maximum)) + { + v.Maximum = (int)a.Maximum; + } + if (a.ExclusiveMaximum) + { + v.ExclusiveMaximum = a.ExclusiveMaximum; + } + if (a.MultipleOf != 0) + { + v.MultipleOf = (int)a.MultipleOf; + } + } + return v; + } + + case ValueNodeType.Number: + { + var v = new JsonNumberValidator(); + if (a != null) + { + if (!double.IsNaN(a.Minimum)) + { + v.Minimum = (int)a.Minimum; + } + if (a.ExclusiveMinimum) + { + v.ExclusiveMinimum = a.ExclusiveMinimum; + } + if (!double.IsNaN(a.Maximum)) + { + v.Maximum = (int)a.Maximum; + } + if (a.ExclusiveMaximum) + { + v.ExclusiveMaximum = a.ExclusiveMaximum; + } + if (a.MultipleOf != 0) + { + v.MultipleOf = (int)a.MultipleOf; + } + } + return v; + } + + case ValueNodeType.String: + { + var v = new JsonStringValidator(); + if (a != null) + { + if (a.Pattern != null) + { + v.Pattern = new System.Text.RegularExpressions.Regex(a.Pattern); + } + } + return v; + } + + case ValueNodeType.Boolean: + return new JsonBoolValidator(); + + case ValueNodeType.Array: + { + var v = new JsonArrayValidator(); + if (a != null) + { + if (a.MinItems != 0) + { + v.MinItems = a.MinItems; + } + if (a.MaxItems != 0) + { + v.MaxItems = a.MaxItems; + } + + if (t != null) + { + if (ia == null) + { + ia = new ItemJsonSchemaAttribute(); + } + + Type elementType = null; + if (t.IsArray) + { + elementType = t.GetElementType(); + } + else if (t.GetIsGenericList()) + { + elementType = t.GetGenericArguments().First(); + } + + if (elementType != null) + { + /* + var sub = new JsonSchema + { + SkipComparison = ia.SkipSchemaComparison, + Validator = Create(elementType, ia, null) + }; + */ + var sub = JsonSchema.FromType(elementType, ia, null); + v.Items = sub; + } + } + } + return v; + } + + case ValueNodeType.Object: + { + if (t.GetIsGenericDictionary()) + { + var genericFactory = typeof(JsonDictionaryValidator).GetMethod("Create", BindingFlags.Static | BindingFlags.Public); + var factory = genericFactory.MakeGenericMethod(t.GetGenericArguments()[1]); + var v = factory.Invoke(null, null) as IJsonSchemaValidator; + return v; + } + else + { + var v = new JsonObjectValidator(); + if (a != null) + { + if (a.MinProperties > 0) + { + v.MinProperties = a.MinProperties; + } + + // props + foreach (var prop in GetProperties(t, a.ExportFlags)) + { + v.Properties.Add(prop.Key, prop.Schema); + if (prop.Required) + { + v.Required.Add(prop.Key); + } + if (prop.Dependencies != null) + { + v.Dependencies.Add(prop.Key, prop.Dependencies); + } + } + + } + + if (ia != null) + { + var sub = new JsonSchema + { + SkipComparison = ia.SkipSchemaComparison, + Validator = Create(typeof(object), ia, null) + }; + v.AdditionalProperties = sub; + } + + return v; + } + } + + default: + throw new NotImplementedException(); + } + } + + public static IJsonSchemaValidator Create(string t) + { + return Create((ValueNodeType)Enum.Parse(typeof(ValueNodeType), t, true)); + } + + static Dictionary s_typeMap = new Dictionary + { + {typeof(byte), ValueNodeType.Integer }, + {typeof(short), ValueNodeType.Integer }, + {typeof(int), ValueNodeType.Integer }, + {typeof(long), ValueNodeType.Integer }, + {typeof(sbyte), ValueNodeType.Integer }, + {typeof(ushort), ValueNodeType.Integer }, + {typeof(uint), ValueNodeType.Integer }, + {typeof(ulong), ValueNodeType.Integer }, + {typeof(float), ValueNodeType.Number }, + {typeof(double), ValueNodeType.Number }, + {typeof(string), ValueNodeType.String }, + {typeof(bool), ValueNodeType.Boolean }, + + // Unity types + {typeof(Vector3), ValueNodeType.Object }, + }; + + static ValueNodeType ToJsonType(Type t) + { + ValueNodeType jsonValueType; + if (s_typeMap.TryGetValue(t, out jsonValueType)) + { + return jsonValueType; + } + + if (t.IsArray) + { + return ValueNodeType.Array; + } + if (t.GetIsGenericList()) + { + return ValueNodeType.Array; + } + + //if (t.IsClass) + { + return ValueNodeType.Object; + } + + //throw new NotImplementedException(string.Format("No JsonType for {0}", t)); + } + + public static IJsonSchemaValidator Create(Type t, BaseJsonSchemaAttribute a, ItemJsonSchemaAttribute ia) + { + return Create(ToJsonType(t), t, a, ia); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs.meta b/Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs.meta new file mode 100644 index 000000000..e89965388 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonSchemaValidatorFactory.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9fef66d39a7b22b499bea68e0b22d000 +timeCreated: 1531574156 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/JsonSchemaValidator/JsonStringValidator.cs b/Scripts/JsonSchemaValidator/JsonStringValidator.cs new file mode 100644 index 000000000..aa278ded6 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonStringValidator.cs @@ -0,0 +1,147 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace UniJSON +{ + /// + /// http://json-schema.org/latest/json-schema-validation.html#string + /// + public class JsonStringValidator : IJsonSchemaValidator + { + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.3.1 + /// + public int? MaxLength + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.3.2 + /// + public int? MinLength + { + get; set; + } + + /// + /// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.3.3 + /// + public Regex Pattern + { + get; set; + } + + public override int GetHashCode() + { + return 4; + } + + public override bool Equals(object obj) + { + var rhs = obj as JsonStringValidator; + if (rhs == null) return false; + + if (MaxLength != rhs.MaxLength) return false; + if (MinLength != rhs.MinLength) return false; + + if (Pattern == null && rhs.Pattern == null) + { + } + else if (Pattern == null) + { + return false; + } + else if (rhs.Pattern == null) + { + return false; + } + else if (Pattern.ToString() != rhs.Pattern.ToString()) + { + return false; + } + + return true; + } + + public void Merge(IJsonSchemaValidator obj) + { + var rhs = obj as JsonStringValidator; + if (rhs == null) + { + throw new ArgumentException(); + } + + MaxLength = rhs.MaxLength; + MinLength = rhs.MinLength; + Pattern = rhs.Pattern; + } + + public bool FromJsonSchema(IFileSystemAccessor fs, string key, ListTreeNode value) + { + switch (key) + { + case "maxLength": + MaxLength = value.GetInt32(); + return true; + + case "minLength": + MinLength = value.GetInt32(); + return true; + + case "pattern": + Pattern = new Regex(value.GetString().Replace("\\\\", "\\")); + return true; + } + + return false; + } + + public void ToJsonScheama(IFormatter f) + { + f.Key("type"); f.Value("string"); + } + + public JsonSchemaValidationException Validate(JsonSchemaValidationContext c, T o) + { + if (o == null) + { + return new JsonSchemaValidationException(c, "null"); + } + + var value = o as string; + if (value.All(x => Char.IsWhiteSpace(x))) + { + return new JsonSchemaValidationException(c, "whitespace"); + } + + if (MinLength.HasValue && value.Length < MinLength) + { + return new JsonSchemaValidationException(c, string.Format("minlength: {0}<{1}", value.Length, MinLength.Value)); + } + if (MaxLength.HasValue && value.Length > MaxLength) + { + return new JsonSchemaValidationException(c, string.Format("maxlength: {0}>{1}", value.Length, MaxLength.Value)); + } + + if (Pattern != null && !Pattern.IsMatch(value)) + { + return new JsonSchemaValidationException(c, string.Format("pattern: {0} not match {1}", Pattern, value)); + } + + return null; + } + + public void Serialize(IFormatter f, JsonSchemaValidationContext c, T o) + { + f.Value(GenericCast.Cast(o)); + } + + public void Deserialize(ListTreeNode src, ref U dst) + where T: IListTreeItem, IValue + { + dst = GenericCast.Cast(src.GetString()); + } + } +} diff --git a/Scripts/JsonSchemaValidator/JsonStringValidator.cs.meta b/Scripts/JsonSchemaValidator/JsonStringValidator.cs.meta new file mode 100644 index 000000000..07f08dad4 --- /dev/null +++ b/Scripts/JsonSchemaValidator/JsonStringValidator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0256cc9f46a4e6744826cf5ca0aa1b46 +timeCreated: 1531812574 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode.meta b/Scripts/ListTreeNode.meta new file mode 100644 index 000000000..5127bf90c --- /dev/null +++ b/Scripts/ListTreeNode.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: fa0987f7b38d9eb4b93a22c465570153 +folderAsset: yes +timeCreated: 1545735556 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode/ListTreeNode.cs b/Scripts/ListTreeNode/ListTreeNode.cs new file mode 100644 index 000000000..1ba22a0b1 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNode.cs @@ -0,0 +1,417 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + +namespace UniJSON +{ + public struct ListTreeNode : ITreeNode, T> + where T : IListTreeItem, IValue + { + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override bool Equals(object obj) + { + if (!(obj is ListTreeNode)) + { + return false; + } + + var rhs = (ListTreeNode)obj; + + if ((Value.ValueType == ValueNodeType.Integer || Value.ValueType == ValueNodeType.Null) + && (rhs.Value.ValueType == ValueNodeType.Integer || rhs.Value.ValueType == ValueNodeType.Number)) + { + // ok + } + else if (Value.ValueType != rhs.Value.ValueType) + { + return false; + } + + switch (Value.ValueType) + { + case ValueNodeType.Null: + return true; + + case ValueNodeType.Boolean: + return Value.GetBoolean() == rhs.GetBoolean(); + + case ValueNodeType.Integer: + case ValueNodeType.Number: + return Value.GetDouble() == rhs.GetDouble(); + + case ValueNodeType.String: + return Value.GetString() == rhs.GetString(); + + case ValueNodeType.Array: + return this.ArrayItems().SequenceEqual(rhs.ArrayItems()); + + case ValueNodeType.Object: + { + //var l = ObjectItems().ToDictionary(x => x.Key, x => x.Value); + //var r = rhs.ObjectItems().ToDictionary(x => x.Key, x => x.Value); + //return l.Equals(r); + return this.ObjectItems().OrderBy(x => x.Key.GetUtf8String()).SequenceEqual(rhs.ObjectItems().OrderBy(x => x.Key.GetUtf8String())); + } + } + + return false; + } + + public override string ToString() + { + if (this.IsArray()) + { + var sb = new StringBuilder(); + bool isFirst = true; + sb.Append("["); + /* + foreach (var x in this.ArrayItems()) + { + if (isFirst) + { + isFirst = false; + } + else + { + sb.Append(","); + } + sb.Append(x.ToString()); + } + */ + sb.Append("]"); + return sb.ToString(); + } + else if (this.IsMap()) + { + var sb = new StringBuilder(); + bool isFirst = true; + sb.Append("{"); + /* + foreach (var kv in this.ObjectItems()) + { + if (isFirst) + { + isFirst = false; + } + else + { + sb.Append(","); + } + sb.Append(kv.Key.ToString()); + sb.Append(": "); + sb.Append(kv.Value.ToString()); + } + */ + sb.Append("}"); + return sb.ToString(); + } + else + { + return Value.ToString(); + } + } + + IEnumerable ToString(string indent, int level, bool value = false) + { + if (this.IsArray()) + { + if (!value) for (int i = 0; i < level; ++i) yield return indent; + yield return "[\n"; + + var isFirst = true; + var childLevel = level + 1; + foreach (var x in this.ArrayItems()) + { + if (isFirst) + { + isFirst = false; + } + else + { + yield return ",\n"; + } + + foreach (var y in x.ToString(indent, childLevel)) + { + yield return y; + } + } + if (!isFirst) + { + yield return "\n"; + } + + for (int i = 0; i < level; ++i) yield return indent; + yield return "]"; + } + else if (this.IsMap()) + { + if (!value) for (int i = 0; i < level; ++i) yield return indent; + yield return "{\n"; + + var isFirst = true; + var childLevel = level + 1; + foreach (var kv in this.ObjectItems()) + { + if (isFirst) + { + isFirst = false; + } + else + { + yield return ",\n"; + } + + // key + for (int i = 0; i < childLevel; ++i) yield return indent; + yield return kv.Key.ToString(); + yield return ": "; + + foreach (var y in kv.Value.ToString(indent, childLevel, true)) + { + yield return y; + } + } + if (!isFirst) + { + yield return "\n"; + } + + for (int i = 0; i < level; ++i) yield return indent; + yield return "}"; + } + else + { + if (!value) for (int i = 0; i < level; ++i) yield return indent; + yield return Value.ToString(); + } + } + + public string ToString(string indent) + { + return string.Join("", ToString(indent, 0).ToArray()); + } + + public IEnumerable Diff(ListTreeNode rhs, JsonPointer path = default(JsonPointer)) + { + switch (Value.ValueType) + { + case ValueNodeType.Null: + case ValueNodeType.Boolean: + case ValueNodeType.Number: + case ValueNodeType.Integer: + case ValueNodeType.String: + if (!Equals(rhs)) + { + yield return JsonDiff.Create(this, JsonDiffType.ValueChanged, string.Format("{0} => {1}", Value, rhs.Value)); + } + yield break; + } + + if (Value.ValueType != rhs.Value.ValueType) + { + yield return JsonDiff.Create(this, JsonDiffType.ValueChanged, string.Format("{0} => {1}", Value.ValueType, rhs.Value)); + yield break; + } + + if (Value.ValueType == ValueNodeType.Object) + { + + var l = this.ObjectItems().ToDictionary(x => x.Key, x => x.Value); + var r = rhs.ObjectItems().ToDictionary(x => x.Key, x => x.Value); + + foreach (var kv in l) + { + ListTreeNode x; + if (r.TryGetValue(kv.Key, out x)) + { + r.Remove(kv.Key); + // Found + foreach (var y in kv.Value.Diff(x)) + { + yield return y; + } + } + else + { + // Removed + yield return JsonDiff.Create(kv.Value, JsonDiffType.KeyRemoved, kv.Value.Value.ToString()); + } + } + + foreach (var kv in r) + { + // Addded + yield return JsonDiff.Create(kv.Value, JsonDiffType.KeyAdded, kv.Value.Value.ToString()); + } + } + else if (Value.ValueType == ValueNodeType.Array) + { + var ll = this.ArrayItems().GetEnumerator(); + var rr = rhs.ArrayItems().GetEnumerator(); + while (true) + { + var lll = ll.MoveNext(); + var rrr = rr.MoveNext(); + if (lll && rrr) + { + // found + foreach (var y in ll.Current.Diff(rr.Current)) + { + yield return y; + } + } + else if (lll) + { + yield return JsonDiff.Create(ll.Current, JsonDiffType.KeyRemoved, ll.Current.Value.ToString()); + } + else if (rrr) + { + yield return JsonDiff.Create(rr.Current, JsonDiffType.KeyAdded, rr.Current.Value.ToString()); + } + else + { + // end + break; + } + } + } + else + { + throw new NotImplementedException(); + } + } + + /// + /// Whole tree nodes + /// + List m_Values; + public bool IsValid + { + get + { + return m_Values != null; + } + } + + /// + /// This node index + /// + public int ValueIndex + { + get; + private set; + } + + public ListTreeNode Prev + { + get + { + return new ListTreeNode(m_Values, ValueIndex - 1); + } + } + + public T Value + { + get + { + if (m_Values == null) + { + return default(T); + } + return m_Values[ValueIndex]; + } + } + public void SetValue(T value) + { + m_Values[ValueIndex] = value; + } + + #region Children + public IEnumerable> Children + { + get + { + for (int i = 0; i < m_Values.Count; ++i) + { + if (m_Values[i].ParentIndex == ValueIndex) + { + yield return new ListTreeNode(m_Values, i); + } + } + } + } + + public ListTreeNode this[String key] + { + get + { + return this[Utf8String.From(key)]; + } + } + + public ListTreeNode this[Utf8String key] + { + get + { + return this.GetObjectItem(key); + } + } + + public ListTreeNode this[int index] + { + get + { + return this.GetArrrayItem(index); + } + } + #endregion + + public bool HasParent + { + get + { + return Value.ParentIndex >= 0 && Value.ParentIndex < m_Values.Count; + } + } + public ListTreeNode Parent + { + get + { + if (Value.ParentIndex < 0) + { + throw new Exception("no parent"); + } + if (Value.ParentIndex >= m_Values.Count) + { + throw new IndexOutOfRangeException(); + } + return new ListTreeNode(m_Values, Value.ParentIndex); + } + } + + public ListTreeNode(List values, int index = 0) : this() + { + m_Values = values; + ValueIndex = index; + } + + #region JsonPointer + public void AddKey(Utf8String key) + { + m_Values.Add(default(T).Key(key, ValueIndex)); + } + + public void AddValue(ArraySegment bytes, ValueNodeType valueType) + { + m_Values.Add(default(T).New(bytes, valueType, ValueIndex)); + } + #endregion + } +} diff --git a/Scripts/ListTreeNode/ListTreeNode.cs.meta b/Scripts/ListTreeNode/ListTreeNode.cs.meta new file mode 100644 index 000000000..4c618acd8 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 26f90c47d985b3e4c8cf153607f9fb31 +timeCreated: 1545735556 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs b/Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs new file mode 100644 index 000000000..2a87b7a4d --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; + + +namespace UniJSON +{ + public static class ListTreeNodeArrayExtensions + { + public static IEnumerable> ArrayItems(this ListTreeNode self) where T : IListTreeItem, IValue + { + if (!self.IsArray()) throw new DeserializationException("is not array"); + return self.Children; + } + + public static ListTreeNode GetArrrayItem(this ListTreeNode self, int index) + where T : IListTreeItem, IValue + { + int i = 0; + foreach (var v in self.ArrayItems()) + { + if (i++ == index) + { + return v; + } + } + throw new KeyNotFoundException(); + } + + public static int GetArrayCount(this ListTreeNode self) + where T : IListTreeItem, IValue + { + if (!self.IsArray()) throw new DeserializationException("is not array"); + return self.Children.Count(); + } + + public static int IndexOf(this ListTreeNode self, ListTreeNode child) + where T : IListTreeItem, IValue + { + int i = 0; + foreach (var v in self.ArrayItems()) + { + if (v.ValueIndex == child.ValueIndex) + { + return i; + } + ++i; + } + throw new KeyNotFoundException(); + } + } +} diff --git a/Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs.meta b/Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs.meta new file mode 100644 index 000000000..4e8bb2806 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeArrayExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0633f1f90105acc41b82ef809fe4ebbd +timeCreated: 1545735556 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs b/Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs new file mode 100644 index 000000000..09883fa16 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + + +namespace UniJSON +{ + public static class ListTreeNodeDeserializerExtensions + { + struct GenericCreator + where T : IListTreeItem, IValue + { + static V[] ArrayCreator(ListTreeNode src) + { + if (!src.IsArray()) + { + throw new ArgumentException("value is not array"); + } + var count = src.GetArrayCount(); + return new V[count]; + } + + static Func, U> GetCreator() + { + var t = typeof(U); + if (t.IsArray) + { + var mi = typeof(GenericCreator).GetMethod("ArrayCreator", + BindingFlags.NonPublic | BindingFlags.Static); + var g = mi.MakeGenericMethod(t.GetElementType()); + var src = Expression.Parameter(typeof(T), "src"); + var call = Expression.Call(g, src); + var func = Expression.Lambda(call, src); + return (Func, U>)func.Compile(); + } + + { + return _s => + { + return Activator.CreateInstance(); + }; + } + } + + delegate U Creator(ListTreeNode src); + + static Creator s_creator; + + public U Create(ListTreeNode src) + { + if (s_creator == null) + { + var d = GetCreator(); + s_creator = new Creator(d); + } + return s_creator(src); + } + } + + static object DictionaryDeserializer(ListTreeNode s) + where T : IListTreeItem, IValue + { + switch (s.Value.ValueType) + { + case ValueNodeType.Object: + { + var u = new Dictionary(); + foreach (var kv in s.ObjectItems()) + { + //var e = default(object); + //kv.Value.Deserialize(ref e); + u.Add(kv.Key.GetString(), DictionaryDeserializer(kv.Value)); + } + return u; + } + + case ValueNodeType.Null: + return null; + + case ValueNodeType.Boolean: + return s.GetBoolean(); + + case ValueNodeType.Integer: + return s.GetInt32(); + + case ValueNodeType.Number: + return s.GetDouble(); + + case ValueNodeType.String: + return s.GetString(); + + default: + throw new NotImplementedException(s.Value.ValueType.ToString()); + } + } + + public static void Deserialize(this ListTreeNode self, ref U value) + where T : IListTreeItem, IValue + { + GenericDeserializer.Deserialize(self, ref value); + } + } + + public static class GenericDeserializer + where T : IListTreeItem, IValue + { + static V[] GenericArrayDeserializer(ListTreeNode s) + { + if (!s.IsArray()) + { + throw new ArgumentException("not array: " + s.Value.ValueType); + } + var u = new V[s.GetArrayCount()]; + int i = 0; + foreach (var x in s.ArrayItems()) + { + x.Deserialize(ref u[i++]); + } + return u; + } + + static List GenericListDeserializer(ListTreeNode s) + { + if (!s.IsArray()) + { + throw new ArgumentException("not array: " + s.Value.ValueType); + } + var u = new List(s.GetArrayCount()); + foreach (var x in s.ArrayItems()) + { + var e = default(V); + x.Deserialize(ref e); + u.Add(e); + } + return u; + } + + delegate void FieldSetter(ListTreeNode s, object o); + static FieldSetter GetFieldDeserializer(FieldInfo fi) + { + return (s, o) => + { + var u = default(V); + s.Deserialize(ref u); + fi.SetValue(o, u); + }; + } + + static Func, U> GetDeserializer() + { + // primitive + { + var mi = typeof(ListTreeNode).GetMethods().FirstOrDefault(x => + { + if (!x.Name.StartsWith("Get")) + { + return false; + } + + if (!x.Name.EndsWith(typeof(U).Name)) + { + return false; + } + + var parameters = x.GetParameters(); + if (parameters.Length != 0) + { + return false; + } + + if (x.ReturnType != typeof(U)) + { + return false; + } + + return true; + }); + + if (mi != null) + { + var self = Expression.Parameter(typeof(ListTreeNode), "self"); + var call = Expression.Call(self, mi); + var func = Expression.Lambda(call, self); + return (Func, U>)func.Compile(); + } + } + + var target = typeof(U); + + if (target.IsArray) + { + var mi = typeof(GenericDeserializer).GetMethod("GenericArrayDeserializer", + BindingFlags.Static | BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(target.GetElementType()); + var self = Expression.Parameter(typeof(ListTreeNode), "self"); + var call = Expression.Call(g, self); + var func = Expression.Lambda(call, self); + return (Func, U>)func.Compile(); + } + + if (target.IsGenericType) + { + if (target.GetGenericTypeDefinition() == typeof(List<>)) + { + var mi = typeof(GenericDeserializer).GetMethod("GenericListDeserializer", + BindingFlags.Static | BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(target.GetGenericArguments()); + var self = Expression.Parameter(typeof(ListTreeNode), "self"); + var call = Expression.Call(g, self); + var func = Expression.Lambda(call, self); + return (Func, U>)func.Compile(); + } + + if (target.GetGenericTypeDefinition() == typeof(Dictionary<,>) && + target.GetGenericArguments()[0] == typeof(string)) + { + var mi = typeof(ListTreeNodeDeserializerExtensions).GetMethod("DictionaryDeserializer", + BindingFlags.Static | BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(typeof(T)); + var self = Expression.Parameter(typeof(ListTreeNode), "self"); + var call = Expression.Call(g, self); + var func = Expression.Lambda(call, self); + var d = (Func, object>)func.Compile(); + return (ListTreeNode s) => + { + var x = d(s); + return (U)x; + }; + } + } + + { + var schema = JsonSchema.FromType(); + return s => + { + var t = default(U); + schema.Validator.Deserialize(s, ref t); + return t; + }; + } + +#if false + if (target.IsEnum) + { + var value = Expression.Parameter(typeof(int), "value"); + var cast = Expression.Convert(value, target); + var func = Expression.Lambda(cast, value); + var compiled = (Func)func.Compile(); + return s => + { + return compiled(s.GetInt32()); + }; + } + + { + var fields = target.GetFields(BindingFlags.Instance | BindingFlags.Public); + var fieldDeserializers = fields.ToDictionary(x => Utf8String.From(x.Name), x => + { + var mi = typeof(GenericDeserializer).GetMethod("GetFieldDeserializer", + BindingFlags.Static|BindingFlags.NonPublic); + var g = mi.MakeGenericMethod(x.FieldType); + return (FieldSetter)g.Invoke(null, new object[] { x }); + }); + + return (S s) => + { + if (!s.IsMap()) + { + throw new ArgumentException(s.ValueType.ToString()); + } + + var t = (object)default(GenericCreator).Create(s); + foreach(var kv in s.ObjectItems()) + { + FieldSetter setter; + if (fieldDeserializers.TryGetValue(kv.Key, out setter)) + { + setter(kv.Value, t); + } + } + return (T)t; + }; + } +#endif + } + + public delegate U Deserializer(ListTreeNode node); + + public static Deserializer s_deserializer; + + public static void Deserialize(ListTreeNode node, ref U value) + { + if (s_deserializer == null) + { + var d = GetDeserializer(); + s_deserializer = new Deserializer(d); + } + value = s_deserializer(node); + } + + public static void SetCustomDeserializer(Deserializer deserializer) + { + s_deserializer = deserializer; + } + } +} diff --git a/Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs.meta b/Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs.meta new file mode 100644 index 000000000..e7edfeb77 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeDeserializerExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 961c1bf9650027347a1279c4f04a1feb +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode/ListTreeNodeExtensions.cs b/Scripts/ListTreeNode/ListTreeNodeExtensions.cs new file mode 100644 index 000000000..8523601ac --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeExtensions.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; + + +namespace UniJSON +{ + public static class ListTreeNodeExtensions + { + #region IValue + public static bool IsNull(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.Null; + } + + public static bool IsBoolean(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.Boolean; + } + + public static bool IsString(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.String; + } + + public static bool IsInteger(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.Integer; + } + + public static bool IsFloat(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.Number + || self.Value.ValueType == ValueNodeType.NaN + || self.Value.ValueType == ValueNodeType.Infinity + || self.Value.ValueType == ValueNodeType.MinusInfinity; + } + + public static bool IsArray(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.Array; + } + + public static bool IsMap(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.ValueType == ValueNodeType.Object; + } + + public static bool GetBoolean(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetBoolean(); } + public static string GetString(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetString(); } + public static Utf8String GetUtf8String(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetUtf8String(); } + public static sbyte GetSByte(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetSByte(); } + public static short GetInt16(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetInt16(); } + public static int GetInt32(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetInt32(); } + public static long GetInt64(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetInt64(); } + public static byte GetByte(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetByte(); } + public static ushort GetUInt16(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetUInt16(); } + public static uint GetUInt32(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetUInt32(); } + public static ulong GetUInt64(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetUInt64(); } + public static float GetSingle(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetSingle(); } + public static double GetDouble(this ListTreeNode self) where T : IListTreeItem, IValue { return self.Value.GetDouble(); } + + /// + /// for UnitTest. Use explicit GetT() or Deserialize(ref T) + /// + /// + public static object GetValue(this ListTreeNode self) where T : IListTreeItem, IValue + { + return self.Value.GetValue(); + } + #endregion + + public static IEnumerable> Traverse(this ListTreeNode self) where T : IListTreeItem, IValue + { + yield return self; + if (self.IsArray()) + { + foreach (var x in self.ArrayItems()) + { + foreach (var y in x.Traverse()) + { + yield return y; + } + } + } + else if (self.IsMap()) + { + foreach (var kv in self.ObjectItems()) + { + foreach (var y in kv.Value.Traverse()) + { + yield return y; + } + } + } + } + } +} diff --git a/Scripts/ListTreeNode/ListTreeNodeExtensions.cs.meta b/Scripts/ListTreeNode/ListTreeNodeExtensions.cs.meta new file mode 100644 index 000000000..a08c1a305 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a612ae688d8bc844aa89f13109b665d3 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs b/Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs new file mode 100644 index 000000000..2629338b5 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace UniJSON +{ + public static class ListTreeNodeJsonPointerExtensions + { + public static void SetValue(this ListTreeNode self, + Utf8String jsonPointer, ArraySegment bytes) + where T: IListTreeItem, IValue + { + foreach (var node in self.GetNodes(jsonPointer)) + { + node.SetValue(default(T).New( + bytes, + ValueNodeType.Boolean, + node.Value.ParentIndex)); + } + } + + public static void RemoveValue(this ListTreeNode self, Utf8String jsonPointer) + where T : IListTreeItem, IValue + { + foreach (var node in self.GetNodes(new JsonPointer(jsonPointer))) + { + if (node.Parent.IsMap()) + { + node.Prev.SetValue(default(T)); // remove key + } + node.SetValue(default(T)); // remove + } + } + + public static JsonPointer Pointer(this ListTreeNode self) + where T: IListTreeItem, IValue + { + return JsonPointer.Create(self); + } + + public static IEnumerable> Path(this ListTreeNode self) + where T : IListTreeItem, IValue + { + if (self.HasParent) + { + foreach (var x in self.Parent.Path()) + { + yield return x; + } + } + yield return self; + } + + public static IEnumerable> GetNodes(this ListTreeNode self, + JsonPointer jsonPointer) + where T : IListTreeItem, IValue + { + if (jsonPointer.Path.Count == 0) + { + yield return self; + yield break; + } + + if (self.IsArray()) + { + // array + if (jsonPointer[0][0] == '*') + { + // wildcard + foreach (var child in self.ArrayItems()) + { + foreach (var childChild in child.GetNodes(jsonPointer.Unshift())) + { + yield return childChild; + } + } + } + else + { + int index = jsonPointer[0].ToInt32(); + var child = self.ArrayItems().Skip(index).First(); + foreach (var childChild in child.GetNodes(jsonPointer.Unshift())) + { + yield return childChild; + } + } + } + else if (self.IsMap()) + { + // object + if (jsonPointer[0][0] == '*') + { + // wildcard + foreach (var kv in self.ObjectItems()) + { + foreach (var childChild in kv.Value.GetNodes(jsonPointer.Unshift())) + { + yield return childChild; + } + } + } + else + { + ListTreeNode child; + try + { + child = self.ObjectItems().First(x => x.Key.GetUtf8String() == jsonPointer[0]).Value; + } + catch (Exception) + { + // key + self.AddKey(jsonPointer[0]); + // value + self.AddValue(default(ArraySegment), ValueNodeType.Object); + + child = self.ObjectItems().First(x => x.Key.GetUtf8String() == jsonPointer[0]).Value; + } + foreach (var childChild in child.GetNodes(jsonPointer.Unshift())) + { + yield return childChild; + } + } + } + else + { + throw new NotImplementedException(); + } + } + + public static IEnumerable> GetNodes(this ListTreeNode self, + Utf8String jsonPointer) + where T : IListTreeItem, IValue + { + return self.GetNodes(new JsonPointer(jsonPointer)); + } + } +} diff --git a/Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta b/Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta new file mode 100644 index 000000000..4359c836d --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeJsonPointerExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 20e02dc7c390454448d4a3ce7aca4d17 +timeCreated: 1545735556 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs b/Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs new file mode 100644 index 000000000..c014ccaeb --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace UniJSON +{ + public static class IValueNodeObjectExtensions + { + public static IEnumerable, ListTreeNode>> ObjectItems(this ListTreeNode self) + where T : IListTreeItem, IValue + { + if (!self.IsMap()) throw new DeserializationException("is not object"); + var it = self.Children.GetEnumerator(); + while (it.MoveNext()) + { + var key = it.Current; + + it.MoveNext(); + yield return new KeyValuePair, ListTreeNode>(key, it.Current); + } + } + + public static int GetObjectCount(this ListTreeNode self) + where T : IListTreeItem, IValue + { + if (!self.IsMap()) throw new DeserializationException("is not object"); + return self.Children.Count() / 2; + } + + public static ListTreeNode GetObjectItem(this ListTreeNode self, String key) + where T : IListTreeItem, IValue + { + return self.GetObjectItem(Utf8String.From(key)); + } + + public static ListTreeNode GetObjectItem(this ListTreeNode self, Utf8String key) + where T : IListTreeItem, IValue + + { + foreach (var kv in self.ObjectItems()) + { + if (kv.Key.GetUtf8String() == key) + { + return kv.Value; + } + } + throw new KeyNotFoundException(); + } + + public static bool ContainsKey(this ListTreeNode self, Utf8String key) + where T : IListTreeItem, IValue + { + return self.ObjectItems().Any(x => x.Key.GetUtf8String() == key); + } + + public static bool ContainsKey(this ListTreeNode self, String key) + where T : IListTreeItem, IValue + { + var ukey = Utf8String.From(key); + return self.ContainsKey(ukey); + } + + public static Utf8String KeyOf(this ListTreeNode self, ListTreeNode node) + where T : IListTreeItem, IValue + { + foreach (var kv in self.ObjectItems()) + { + if (node.ValueIndex == kv.Value.ValueIndex) + { + return kv.Key.GetUtf8String(); + } + } + throw new KeyNotFoundException(); + } + } +} diff --git a/Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs.meta b/Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs.meta new file mode 100644 index 000000000..ba8470a39 --- /dev/null +++ b/Scripts/ListTreeNode/ListTreeNodeObjectExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b3b4670381937134c9ce96d058f2f730 +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack.meta b/Scripts/MsgPack.meta new file mode 100644 index 000000000..d1df7e374 --- /dev/null +++ b/Scripts/MsgPack.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c2497653b22017547b01e854b0fa540d +folderAsset: yes +timeCreated: 1540812361 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/EndianConverter.cs b/Scripts/MsgPack/EndianConverter.cs new file mode 100644 index 000000000..4caf12919 --- /dev/null +++ b/Scripts/MsgPack/EndianConverter.cs @@ -0,0 +1,434 @@ +using System; +using System.Net; + +namespace UniJSON +{ + public static class EndianConverter + { +#if false + /* + #region Converter + /// + /// Read Uint16 From NetworkBytesOrder to HostBytesOrder + /// + /// + /// + public static UInt16 N2H_UInt16(this ArraySegment self) + { + if (BitConverter.IsLittleEndian) + { + return (UInt16)(self.Get(0) << 8 | self.Get(1)); + } + else + { + return BitConverter.ToUInt16(self.Array, self.Offset); + } + } + + public static UInt32 N2H_UInt32(this ArraySegment self) + { + if (BitConverter.IsLittleEndian) + { + return (UInt32)(self.Get(0) << 24 | self.Get(1) << 16 | self.Get(2) << 8 | self.Get(3)); + } + else + { + return BitConverter.ToUInt32(self.Array, self.Offset); + } + } + + public static UInt64 N2H_UInt64(this ArraySegment self) + { + var uvalue = BitConverter.ToUInt64(self.Array, self.Offset); + if (BitConverter.IsLittleEndian) + { + ulong swapped = + ((0x00000000000000FF) & (uvalue >> 56) + | (0x000000000000FF00) & (uvalue >> 40) + | (0x0000000000FF0000) & (uvalue >> 24) + | (0x00000000FF000000) & (uvalue >> 8) + | (0x000000FF00000000) & (uvalue << 8) + | (0x0000FF0000000000) & (uvalue << 24) + | (0x00FF000000000000) & (uvalue << 40) + | (0xFF00000000000000) & (uvalue << 56)); + return swapped; + } + else + { + return uvalue; + } + } + + public static Int16 N2H_Int16(this ArraySegment self) + { + if (BitConverter.IsLittleEndian) + { + return (Int16)(self.Get(0) << 8 | self.Get(1)); + } + else + { + return BitConverter.ToInt16(self.Array, self.Offset); + } + } + + public static Int32 N2H_Int32(this ArraySegment self) + { + if (BitConverter.IsLittleEndian) + { + return (Int32)(self.Get(0) << 24 | self.Get(1) << 16 | self.Get(2) << 8 | self.Get(3)); + } + else + { + return BitConverter.ToInt32(self.Array, self.Offset); + } + } + + public static Int64 N2H_Int64(this ArraySegment self) + { + var value = BitConverter.ToUInt64(self.Array, self.Offset); + if (BitConverter.IsLittleEndian) + { + ulong swapped = + ((0x00000000000000FF) & (value >> 56) + | (0x000000000000FF00) & (value >> 40) + | (0x0000000000FF0000) & (value >> 24) + | (0x00000000FF000000) & (value >> 8) + | (0x000000FF00000000) & (value << 8) + | (0x0000FF0000000000) & (value << 24) + | (0x00FF000000000000) & (value << 40) + | (0xFF00000000000000) & (value << 56)); + return (long)swapped; + } + else + { + return (long)value; + } + } + + public static Single N2H_Single(this ArraySegment self) + { + if (BitConverter.IsLittleEndian) + { + return BitConverter.ToSingle(self.TakeReversedArray(4), 0); + } + else + { + return BitConverter.ToSingle(self.Array, self.Offset); + } + } + + public static Double N2H_Double(this ArraySegment self) + { + return BitConverter.Int64BitsToDouble(self.N2H_Int64()); + } + + public static void N2H_CopyTo(this ArraySegment self, Byte[] buffer, int elementSize) + { + if (buffer.Length < self.Count) throw new ArgumentException(); + + for (int i = 0; i < self.Count; i += elementSize) + { + for (int j = 0; j < elementSize; ++j) + { + buffer[i + j] = self.Get(i + elementSize - 1 - j); + } + } + } + + public static void N2H_CopyTo(this ArraySegment self, Array result, Byte[] buffer) + { + if (BitConverter.IsLittleEndian) + { + if (buffer.Length < self.Count) + { + throw new ArgumentException(); + } + self.N2H_CopyTo(buffer, Marshal.SizeOf(result.GetType().GetElementType())); + + Buffer.BlockCopy(buffer, 0, result, 0, self.Count); + } + else + { + Buffer.BlockCopy(self.Array, self.Offset, result, 0, self.Count); + } + } + #endregion + */ + +#else + #region Signed + public static Int16 NetworkByteWordToSignedNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.WordValue + { + Byte0 = bytes.Get(1), + Byte1 = bytes.Get(0), + }; + return value.Signed; + } + else + { + // Network to Big + var value = new ByteUnion.WordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + }; + return value.Signed; + } + } + public static Int32 NetworkByteDWordToSignedNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.DWordValue + { + Byte0 = bytes.Get(3), + Byte1 = bytes.Get(2), + Byte2 = bytes.Get(1), + Byte3 = bytes.Get(0), + }; + return value.Signed; + } + else + { + // Network to Big + var value = new ByteUnion.DWordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + Byte2 = bytes.Get(2), + Byte3 = bytes.Get(3), + }; + return value.Signed; + } + } + public static Int64 NetworkByteQWordToSignedNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.QWordValue + { + Byte0 = bytes.Get(7), + Byte1 = bytes.Get(6), + Byte2 = bytes.Get(5), + Byte3 = bytes.Get(4), + Byte4 = bytes.Get(3), + Byte5 = bytes.Get(2), + Byte6 = bytes.Get(1), + Byte7 = bytes.Get(0), + }; + return value.Signed; + } + else + { + // Network to Big + var value = new ByteUnion.QWordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + Byte2 = bytes.Get(2), + Byte3 = bytes.Get(3), + Byte4 = bytes.Get(4), + Byte5 = bytes.Get(5), + Byte6 = bytes.Get(6), + Byte7 = bytes.Get(7), + }; + return value.Signed; + } + } + #endregion + #region Unsigned + public static UInt16 NetworkByteWordToUnsignedNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.WordValue + { + Byte0 = bytes.Get(1), + Byte1 = bytes.Get(0), + }; + return value.Unsigned; + } + else + { + // Network to Big + var value = new ByteUnion.WordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + }; + return value.Unsigned; + } + } + public static UInt32 NetworkByteDWordToUnsignedNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.DWordValue + { + Byte0 = bytes.Get(3), + Byte1 = bytes.Get(2), + Byte2 = bytes.Get(1), + Byte3 = bytes.Get(0), + }; + return value.Unsigned; + } + else + { + // Network to Big + var value = new ByteUnion.DWordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + Byte2 = bytes.Get(2), + Byte3 = bytes.Get(3), + }; + return value.Unsigned; + } + } + public static UInt64 NetworkByteQWordToUnsignedNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.QWordValue + { + Byte0 = bytes.Get(7), + Byte1 = bytes.Get(6), + Byte2 = bytes.Get(5), + Byte3 = bytes.Get(4), + Byte4 = bytes.Get(3), + Byte5 = bytes.Get(2), + Byte6 = bytes.Get(1), + Byte7 = bytes.Get(0), + }; + return value.Unsigned; + } + else + { + // Network to Big + var value = new ByteUnion.QWordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + Byte2 = bytes.Get(2), + Byte3 = bytes.Get(3), + Byte4 = bytes.Get(4), + Byte5 = bytes.Get(5), + Byte6 = bytes.Get(6), + Byte7 = bytes.Get(7), + }; + return value.Unsigned; + } + } + #endregion + #region Floating + public static Single NetworkByteDWordToFloatNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.DWordValue + { + Byte0 = bytes.Get(3), + Byte1 = bytes.Get(2), + Byte2 = bytes.Get(1), + Byte3 = bytes.Get(0), + }; + return value.Float; + } + else + { + // Network to Big + var value = new ByteUnion.DWordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + Byte2 = bytes.Get(2), + Byte3 = bytes.Get(3), + }; + return value.Float; + } + } + public static Double NetworkByteQWordToFloatNativeByteOrder(ArraySegment bytes) + { + if (BitConverter.IsLittleEndian) + { + // Network to Little + var value = new ByteUnion.QWordValue + { + Byte0 = bytes.Get(7), + Byte1 = bytes.Get(6), + Byte2 = bytes.Get(5), + Byte3 = bytes.Get(4), + Byte4 = bytes.Get(3), + Byte5 = bytes.Get(2), + Byte6 = bytes.Get(1), + Byte7 = bytes.Get(0), + }; + return value.Float; + } + else + { + // Network to Big + var value = new ByteUnion.QWordValue + { + Byte0 = bytes.Get(0), + Byte1 = bytes.Get(1), + Byte2 = bytes.Get(2), + Byte3 = bytes.Get(3), + Byte4 = bytes.Get(4), + Byte5 = bytes.Get(5), + Byte6 = bytes.Get(6), + Byte7 = bytes.Get(7), + }; + return value.Float; + } + } + #endregion +#endif + + public static Int16 ToNetworkByteOrder(this Int16 value) + { + return ByteUnion.WordValue.Create(value).HostToNetworkOrder().Signed; + } + public static UInt16 ToNetworkByteOrder(this UInt16 value) + { + return ByteUnion.WordValue.Create(value).HostToNetworkOrder().Unsigned; + } + + public static Int32 ToNetworkByteOrder(this Int32 value) + { + return ByteUnion.DWordValue.Create(value).HostToNetworkOrder().Signed; + } + public static UInt32 ToNetworkByteOrder(this UInt32 value) + { + return ByteUnion.DWordValue.Create(value).HostToNetworkOrder().Unsigned; + } + public static Single ToNetworkByteOrder(this Single value) + { + return ByteUnion.DWordValue.Create(value).HostToNetworkOrder().Float; + } + + public static Int64 ToNetworkByteOrder(this Int64 value) + { + return ByteUnion.QWordValue.Create(value).HostToNetworkOrder().Signed; + } + public static UInt64 ToNetworkByteOrder(this UInt64 value) + { + return ByteUnion.QWordValue.Create(value).HostToNetworkOrder().Unsigned; + } + public static Double ToNetworkByteOrder(this Double value) + { + return ByteUnion.QWordValue.Create(value).HostToNetworkOrder().Float; + } + } +} diff --git a/Scripts/MsgPack/EndianConverter.cs.meta b/Scripts/MsgPack/EndianConverter.cs.meta new file mode 100644 index 000000000..f6008eb96 --- /dev/null +++ b/Scripts/MsgPack/EndianConverter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2d72520a65b562f4f862ac0760306215 +timeCreated: 1540879367 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/Exceptions.cs b/Scripts/MsgPack/Exceptions.cs new file mode 100644 index 000000000..75e496646 --- /dev/null +++ b/Scripts/MsgPack/Exceptions.cs @@ -0,0 +1,13 @@ +using System; + +namespace UniJSON +{ + + public class MsgPackTypeException : Exception + { + public MsgPackTypeException(string msg) : base(msg) + { } + + } + +} \ No newline at end of file diff --git a/Scripts/MsgPack/Exceptions.cs.meta b/Scripts/MsgPack/Exceptions.cs.meta new file mode 100644 index 000000000..76095e45c --- /dev/null +++ b/Scripts/MsgPack/Exceptions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bc09dae63ba521545a0b9a8ef120b95a +timeCreated: 1540906879 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/MsgPackFormatter.cs b/Scripts/MsgPack/MsgPackFormatter.cs new file mode 100644 index 000000000..ee1aa7ebb --- /dev/null +++ b/Scripts/MsgPack/MsgPackFormatter.cs @@ -0,0 +1,600 @@ +using System; +using System.Text; + + +namespace UniJSON +{ + public class MsgPackFormatter : IFormatter, IRpc + { + IStore m_store; + public MsgPackFormatter(IStore store) + { + m_store = store; + } + + public MsgPackFormatter() : this(new BytesStore()) + { + } + +#if false + public bool MsgPack_Ext(IList list) + { + var t = list.GetType(); + var et = t.GetElementType(); + if (et.IsClass()) + { + return false; + } + m_store.Write((Byte)MsgPackType.EXT32); + var itemSize = Marshal.SizeOf(et); + WriteInt32_NBO(list.Count * itemSize); + + Action pack; + if (et == typeof(UInt16)) + { + m_store.Write((Byte)ExtType.UINT16_BE); + pack = o => WriteUInt16_NBO((UInt16)o); + } + else if (et == typeof(UInt32)) + { + m_store.Write((Byte)ExtType.UINT32_BE); + pack = o => WriteUInt32_NBO((UInt32)o); + } + else if (et == typeof(UInt64)) + { + m_store.Write((Byte)ExtType.UINT64_BE); + pack = o => WriteUInt64_NBO((UInt64)o); + } + else if (et == typeof(Int16)) + { + m_store.Write((Byte)ExtType.INT16_BE); + pack = o => WriteInt16_NBO((Int16)o); + } + else if (et == typeof(Int32)) + { + m_store.Write((Byte)ExtType.INT32_BE); + pack = o => WriteInt32_NBO((Int32)o); + } + else if (et == typeof(Int64)) + { + m_store.Write((Byte)ExtType.INT64_BE); + pack = o => WriteInt64_NBO((Int64)o); + } + else if (et == typeof(Single)) + { + m_store.Write((Byte)ExtType.SINGLE_BE); + pack = o => WriteSingle_NBO((Single)o); + } + else if (et == typeof(Double)) + { + m_store.Write((Byte)ExtType.DOUBLE_BE); + pack = o => WriteDouble_NBO((Double)o); + } + else + { + return false; + } + + foreach (var i in list) + { + pack(i); + } + return true; + } +#endif + + public void BeginList(int n) + { + if (n < 0x0F) + { + m_store.Write((Byte)((Byte)MsgPackType.FIX_ARRAY | n)); + } + else if (n < 0xFFFF) + { + m_store.Write((Byte)MsgPackType.ARRAY16); + m_store.WriteBigEndian((UInt16)n); + } + else + { + m_store.Write((Byte)MsgPackType.ARRAY32); + m_store.WriteBigEndian(n); + } + } + + public void EndList() + { + } + + public void BeginMap(int n) + { + if (n < 0x0F) + { + m_store.Write((Byte)((Byte)MsgPackType.FIX_MAP | n)); + } + else if (n < 0xFFFF) + { + m_store.Write((Byte)MsgPackType.MAP16); + m_store.WriteBigEndian((UInt16)n); + } + else + { + m_store.Write((Byte)MsgPackType.MAP32); + m_store.WriteBigEndian(n.ToNetworkByteOrder()); + } + } + + public void EndMap() + { + } + + public void Null() + { + m_store.Write((Byte)MsgPackType.NIL); + } + + public void Key(Utf8String key) + { + Value(key); + } + + public void Value(String s) + { + Value(Utf8String.From(s)); + } + + public void Value(Utf8String s) + { + var bytes = s.Bytes; + int size = bytes.Count; + if (size < 32) + { + m_store.Write((Byte)((Byte)MsgPackType.FIX_STR | size)); + m_store.Write(bytes); + } + else if (size < 0xFF) + { + m_store.Write((Byte)(MsgPackType.STR8)); + m_store.Write((Byte)(size)); + m_store.Write(bytes); + } + else if (size < 0xFFFF) + { + m_store.Write((Byte)MsgPackType.STR16); + m_store.WriteBigEndian((UInt16)size); + m_store.Write(bytes); + } + else + { + m_store.Write((Byte)MsgPackType.STR32); + m_store.WriteBigEndian(size); + m_store.Write(bytes); + } + } + + public void Value(bool value) + { + if (value) + { + m_store.Write((Byte)MsgPackType.TRUE); + } + else + { + m_store.Write((Byte)MsgPackType.FALSE); + } + } + + #region Singed + public void Value(sbyte n) + { + if (n >= 0) + { + // positive + Value((Byte)n); + } + else if (n >= -32) + { + var value = (MsgPackType)((n + 32) + (Byte)MsgPackType.NEGATIVE_FIXNUM); + m_store.Write((Byte)value); + } + else + { + m_store.Write((Byte)MsgPackType.INT8); + m_store.Write((Byte)n); + } + } + + public void Value(short n) + { + if (n >= 0) + { + // positive + if (n <= 0xFF) + { + Value((Byte)n); + } + else + { + Value((UInt16)n); + } + } + else + { + // negative + if (n >= -128) + { + m_store.Write((SByte)n); + } + else + { + m_store.Write((Byte)MsgPackType.INT16); + m_store.WriteBigEndian(n); + } + } + } + + public void Value(int n) + { + if (n >= 0) + { + // positive + if (n <= 0xFF) + { + Value((Byte)n); + } + else if (n <= 0xFFFF) + { + Value((UInt16)n); + } + else + { + Value((UInt32)n); + } + } + else + { + // negative + if (n >= -128) + { + Value((SByte)n); + } + else if (n >= -32768) + { + Value((Int16)n); + } + else + { + m_store.Write((Byte)MsgPackType.INT32); + m_store.WriteBigEndian(n); + } + } + } + + public void Value(long n) + { + if (n >= 0) + { + // positive + if (n <= 0xFF) + { + Value((Byte)n); + } + else if (n <= 0xFFFF) + { + Value((UInt16)n); + } + else if (n <= 0xFFFFFFFF) + { + Value((UInt32)n); + } + else + { + Value((UInt64)n); + } + } + else + { + // negative + if (n >= -128) + { + Value((SByte)n); + } + else if (n >= -32768) + { + Value((Int16)n); + } + else if (n >= -2147483648) + { + Value((Int32)n); + } + else + { + m_store.Write((Byte)MsgPackType.INT64); + m_store.WriteBigEndian(n); + } + } + } + #endregion + + #region Unsigned + public void Value(byte n) + { + if (n <= 0x7F) + { + // FormatType.POSITIVE_FIXNUM + m_store.Write(n); + } + else + { + m_store.Write((Byte)MsgPackType.UINT8); + m_store.Write(n); + } + } + + public void Value(ushort n) + { + if (n <= 0xFF) + { + Value((Byte)n); + } + else + { + m_store.Write((Byte)MsgPackType.UINT16); + m_store.WriteBigEndian(n); + } + } + + public void Value(uint n) + { + if (n <= 0xFF) + { + Value((Byte)n); + } + else if (n <= 0xFFFF) + { + Value((UInt16)n); + } + else + { + m_store.Write((Byte)MsgPackType.UINT32); + m_store.WriteBigEndian(n); + } + } + + public void Value(ulong n) + { + if (n <= 0xFF) + { + Value((Byte)n); + } + else if (n <= 0xFFFF) + { + Value((UInt16)n); + } + else if (n <= 0xFFFFFFFF) + { + Value((UInt32)n); + } + else + { + m_store.Write((Byte)MsgPackType.UINT64); + m_store.WriteBigEndian(n); + } + } + #endregion + + public void Value(float value) + { + m_store.Write((Byte)MsgPackType.FLOAT); + m_store.WriteBigEndian(value); + } + + public void Value(double value) + { + m_store.Write((Byte)MsgPackType.DOUBLE); + m_store.WriteBigEndian(value); + } + + public void Value(ArraySegment bytes) + { + if (bytes.Count < 0xFF) + { + m_store.Write((Byte)(MsgPackType.BIN8)); + m_store.Write((Byte)(bytes.Count)); + m_store.Write(bytes); + } + else if (bytes.Count < 0xFFFF) + { + m_store.Write((Byte)MsgPackType.BIN16); + m_store.WriteBigEndian((UInt16)bytes.Count); + m_store.Write(bytes); + } + else + { + m_store.Write((Byte)MsgPackType.BIN32); + m_store.WriteBigEndian(bytes.Count); + m_store.Write(bytes); + } + } + + public void TimeStamp32(DateTimeOffset time) + { + m_store.Write((Byte)MsgPackType.FIX_EXT_4); + m_store.Write((SByte)(-1)); + m_store.WriteBigEndian((uint)time.ToUnixTimeSeconds()); + } + + public void Value(DateTimeOffset time) + { + TimeStamp32(time); + } + + public void Value(ListTreeNode node) + { + m_store.Write(node.Value.Bytes); + } + + public IStore GetStore() + { + return m_store; + } + + #region IRpc + public const int REQUEST_TYPE = 0; + public const int RESPONSE_TYPE = 1; + public const int NOTIFY_TYPE = 2; + + int m_msgId = 1; + + public void Request(Utf8String method) + { + BeginList(4); + Value(REQUEST_TYPE); + Value(m_msgId++); + Value(method); + BeginList(0); // params + { + } + EndList(); + EndList(); + } + + public void Request(Utf8String method, A0 a0) + { + BeginList(4); + Value(REQUEST_TYPE); + Value(m_msgId++); + Value(method); + BeginList(1); // params + { + this.Serialize(a0); + } + EndList(); + EndList(); + } + + public void Request(Utf8String method, A0 a0, A1 a1) + { + BeginList(4); + Value(REQUEST_TYPE); + Value(m_msgId++); + Value(method); + BeginList(2); // params + { + this.Serialize(a0); + this.Serialize(a1); + } + EndList(); + EndList(); + } + + public void Request(Utf8String method, A0 a0, A1 a1, A2 a2) + { + throw new NotImplementedException(); + } + + public void Request(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3) + { + throw new NotImplementedException(); + } + + public void Request(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) + { + throw new NotImplementedException(); + } + + public void Request(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + throw new NotImplementedException(); + } + + public void ResponseSuccess(int id) + { + BeginList(4); + Value(RESPONSE_TYPE); + Value(id); + Null(); + Null(); + EndList(); + } + + public void ResponseSuccess(int id, T result) + { + BeginList(4); + Value(RESPONSE_TYPE); + Value(id); + Null(); + this.Serialize(result); + EndList(); + } + + public void ResponseError(int id, Exception error) + { + BeginList(4); + Value(RESPONSE_TYPE); + Value(id); + this.Serialize(error); + Null(); + EndList(); + } + + public void Notify(Utf8String method) + { + BeginList(3); + Value(NOTIFY_TYPE); + Value(method); + BeginList(0); // params + { + } + EndList(); + EndList(); + } + + public void Notify(Utf8String method, A0 a0) + { + BeginList(3); + Value(NOTIFY_TYPE); + Value(method); + BeginList(1); // params + { + this.Serialize(a0); + } + EndList(); + EndList(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1) + { + BeginList(3); + Value(NOTIFY_TYPE); + Value(method); + BeginList(2); // params + { + this.Serialize(a0); + this.Serialize(a1); + } + EndList(); + EndList(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2) + { + throw new NotImplementedException(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3) + { + throw new NotImplementedException(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) + { + throw new NotImplementedException(); + } + + public void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + throw new NotImplementedException(); + } + #endregion + } +} diff --git a/Scripts/MsgPack/MsgPackFormatter.cs.meta b/Scripts/MsgPack/MsgPackFormatter.cs.meta new file mode 100644 index 000000000..cdcbc7f3f --- /dev/null +++ b/Scripts/MsgPack/MsgPackFormatter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 41153eff97391fd46a31361bac5804fb +timeCreated: 1540879112 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/MsgPackParser.cs b/Scripts/MsgPack/MsgPackParser.cs new file mode 100644 index 000000000..9d153f589 --- /dev/null +++ b/Scripts/MsgPack/MsgPackParser.cs @@ -0,0 +1,421 @@ +using System; +using System.Collections.Generic; + +namespace UniJSON +{ + public static class MsgPackParser + { + public static ListTreeNode Parse(Byte[] bytes) + { + return Parse(new ArraySegment(bytes)); + } + + static MsgPackType GetFormat(ArraySegment bytes) + { + return (MsgPackType)bytes.Get(0); + } + + /// + /// Array又はMapの子要素の数を得る + /// + /// + /// + static ArraySegment GetItemCount(ArraySegment bytes, MsgPackType formatType, out UInt32 count) + { + switch (formatType) + { + case MsgPackType.FIX_ARRAY: count = 0; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x1: count = 1; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x2: count = 2; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x3: count = 3; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x4: count = 4; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x5: count = 5; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x6: count = 6; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x7: count = 7; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x8: count = 8; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0x9: count = 9; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0xA: count = 10; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0xB: count = 11; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0xC: count = 12; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0xD: count = 13; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0xE: count = 14; return bytes.Advance(1); + case MsgPackType.FIX_ARRAY_0xF: count = 15; return bytes.Advance(1); + + case MsgPackType.FIX_MAP: count = 0; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x1: count = 1; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x2: count = 2; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x3: count = 3; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x4: count = 4; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x5: count = 5; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x6: count = 6; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x7: count = 7; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x8: count = 8; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0x9: count = 9; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0xA: count = 10; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0xB: count = 11; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0xC: count = 12; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0xD: count = 13; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0xE: count = 14; return bytes.Advance(1); + case MsgPackType.FIX_MAP_0xF: count = 15; return bytes.Advance(1); + + case MsgPackType.ARRAY16: + case MsgPackType.MAP16: + count = EndianConverter.NetworkByteWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 2); + + case MsgPackType.ARRAY32: + case MsgPackType.MAP32: + count = EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 4); + + default: + throw new ArgumentException("is not collection: " + formatType); + } + } + + /// + /// ArrayとMap以外のタイプのペイロードを得る + /// + /// + static ArraySegment GetBody(ArraySegment bytes, MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.FIX_STR: return bytes.Advance(1).Take(0); + case MsgPackType.FIX_STR_0x01: return bytes.Advance(1).Take(1); + case MsgPackType.FIX_STR_0x02: return bytes.Advance(1).Take(2); + case MsgPackType.FIX_STR_0x03: return bytes.Advance(1).Take(3); + case MsgPackType.FIX_STR_0x04: return bytes.Advance(1).Take(4); + case MsgPackType.FIX_STR_0x05: return bytes.Advance(1).Take(5); + case MsgPackType.FIX_STR_0x06: return bytes.Advance(1).Take(6); + case MsgPackType.FIX_STR_0x07: return bytes.Advance(1).Take(7); + case MsgPackType.FIX_STR_0x08: return bytes.Advance(1).Take(8); + case MsgPackType.FIX_STR_0x09: return bytes.Advance(1).Take(9); + case MsgPackType.FIX_STR_0x0A: return bytes.Advance(1).Take(10); + case MsgPackType.FIX_STR_0x0B: return bytes.Advance(1).Take(11); + case MsgPackType.FIX_STR_0x0C: return bytes.Advance(1).Take(12); + case MsgPackType.FIX_STR_0x0D: return bytes.Advance(1).Take(13); + case MsgPackType.FIX_STR_0x0E: return bytes.Advance(1).Take(14); + case MsgPackType.FIX_STR_0x0F: return bytes.Advance(1).Take(15); + + case MsgPackType.FIX_STR_0x10: return bytes.Advance(1).Take(16); + case MsgPackType.FIX_STR_0x11: return bytes.Advance(1).Take(17); + case MsgPackType.FIX_STR_0x12: return bytes.Advance(1).Take(18); + case MsgPackType.FIX_STR_0x13: return bytes.Advance(1).Take(19); + case MsgPackType.FIX_STR_0x14: return bytes.Advance(1).Take(20); + case MsgPackType.FIX_STR_0x15: return bytes.Advance(1).Take(21); + case MsgPackType.FIX_STR_0x16: return bytes.Advance(1).Take(22); + case MsgPackType.FIX_STR_0x17: return bytes.Advance(1).Take(23); + case MsgPackType.FIX_STR_0x18: return bytes.Advance(1).Take(24); + case MsgPackType.FIX_STR_0x19: return bytes.Advance(1).Take(25); + case MsgPackType.FIX_STR_0x1A: return bytes.Advance(1).Take(26); + case MsgPackType.FIX_STR_0x1B: return bytes.Advance(1).Take(27); + case MsgPackType.FIX_STR_0x1C: return bytes.Advance(1).Take(28); + case MsgPackType.FIX_STR_0x1D: return bytes.Advance(1).Take(29); + case MsgPackType.FIX_STR_0x1E: return bytes.Advance(1).Take(30); + case MsgPackType.FIX_STR_0x1F: return bytes.Advance(1).Take(31); + + case MsgPackType.STR8: + case MsgPackType.BIN8: + { + var count = bytes.Get(1); + return bytes.Advance(1 + 1).Take(count); + } + + case MsgPackType.STR16: + case MsgPackType.BIN16: + { + var count = EndianConverter.NetworkByteWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 2).Take(count); + } + + case MsgPackType.STR32: + case MsgPackType.BIN32: + { + var count = EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 4).Take((int)count); + } + + case MsgPackType.NIL: + case MsgPackType.TRUE: + case MsgPackType.FALSE: + case MsgPackType.POSITIVE_FIXNUM: + case MsgPackType.POSITIVE_FIXNUM_0x01: + case MsgPackType.POSITIVE_FIXNUM_0x02: + case MsgPackType.POSITIVE_FIXNUM_0x03: + case MsgPackType.POSITIVE_FIXNUM_0x04: + case MsgPackType.POSITIVE_FIXNUM_0x05: + case MsgPackType.POSITIVE_FIXNUM_0x06: + case MsgPackType.POSITIVE_FIXNUM_0x07: + case MsgPackType.POSITIVE_FIXNUM_0x08: + case MsgPackType.POSITIVE_FIXNUM_0x09: + case MsgPackType.POSITIVE_FIXNUM_0x0A: + case MsgPackType.POSITIVE_FIXNUM_0x0B: + case MsgPackType.POSITIVE_FIXNUM_0x0C: + case MsgPackType.POSITIVE_FIXNUM_0x0D: + case MsgPackType.POSITIVE_FIXNUM_0x0E: + case MsgPackType.POSITIVE_FIXNUM_0x0F: + + case MsgPackType.POSITIVE_FIXNUM_0x10: + case MsgPackType.POSITIVE_FIXNUM_0x11: + case MsgPackType.POSITIVE_FIXNUM_0x12: + case MsgPackType.POSITIVE_FIXNUM_0x13: + case MsgPackType.POSITIVE_FIXNUM_0x14: + case MsgPackType.POSITIVE_FIXNUM_0x15: + case MsgPackType.POSITIVE_FIXNUM_0x16: + case MsgPackType.POSITIVE_FIXNUM_0x17: + case MsgPackType.POSITIVE_FIXNUM_0x18: + case MsgPackType.POSITIVE_FIXNUM_0x19: + case MsgPackType.POSITIVE_FIXNUM_0x1A: + case MsgPackType.POSITIVE_FIXNUM_0x1B: + case MsgPackType.POSITIVE_FIXNUM_0x1C: + case MsgPackType.POSITIVE_FIXNUM_0x1D: + case MsgPackType.POSITIVE_FIXNUM_0x1E: + case MsgPackType.POSITIVE_FIXNUM_0x1F: + + case MsgPackType.POSITIVE_FIXNUM_0x20: + case MsgPackType.POSITIVE_FIXNUM_0x21: + case MsgPackType.POSITIVE_FIXNUM_0x22: + case MsgPackType.POSITIVE_FIXNUM_0x23: + case MsgPackType.POSITIVE_FIXNUM_0x24: + case MsgPackType.POSITIVE_FIXNUM_0x25: + case MsgPackType.POSITIVE_FIXNUM_0x26: + case MsgPackType.POSITIVE_FIXNUM_0x27: + case MsgPackType.POSITIVE_FIXNUM_0x28: + case MsgPackType.POSITIVE_FIXNUM_0x29: + case MsgPackType.POSITIVE_FIXNUM_0x2A: + case MsgPackType.POSITIVE_FIXNUM_0x2B: + case MsgPackType.POSITIVE_FIXNUM_0x2C: + case MsgPackType.POSITIVE_FIXNUM_0x2D: + case MsgPackType.POSITIVE_FIXNUM_0x2E: + case MsgPackType.POSITIVE_FIXNUM_0x2F: + + case MsgPackType.POSITIVE_FIXNUM_0x30: + case MsgPackType.POSITIVE_FIXNUM_0x31: + case MsgPackType.POSITIVE_FIXNUM_0x32: + case MsgPackType.POSITIVE_FIXNUM_0x33: + case MsgPackType.POSITIVE_FIXNUM_0x34: + case MsgPackType.POSITIVE_FIXNUM_0x35: + case MsgPackType.POSITIVE_FIXNUM_0x36: + case MsgPackType.POSITIVE_FIXNUM_0x37: + case MsgPackType.POSITIVE_FIXNUM_0x38: + case MsgPackType.POSITIVE_FIXNUM_0x39: + case MsgPackType.POSITIVE_FIXNUM_0x3A: + case MsgPackType.POSITIVE_FIXNUM_0x3B: + case MsgPackType.POSITIVE_FIXNUM_0x3C: + case MsgPackType.POSITIVE_FIXNUM_0x3D: + case MsgPackType.POSITIVE_FIXNUM_0x3E: + case MsgPackType.POSITIVE_FIXNUM_0x3F: + + case MsgPackType.POSITIVE_FIXNUM_0x40: + case MsgPackType.POSITIVE_FIXNUM_0x41: + case MsgPackType.POSITIVE_FIXNUM_0x42: + case MsgPackType.POSITIVE_FIXNUM_0x43: + case MsgPackType.POSITIVE_FIXNUM_0x44: + case MsgPackType.POSITIVE_FIXNUM_0x45: + case MsgPackType.POSITIVE_FIXNUM_0x46: + case MsgPackType.POSITIVE_FIXNUM_0x47: + case MsgPackType.POSITIVE_FIXNUM_0x48: + case MsgPackType.POSITIVE_FIXNUM_0x49: + case MsgPackType.POSITIVE_FIXNUM_0x4A: + case MsgPackType.POSITIVE_FIXNUM_0x4B: + case MsgPackType.POSITIVE_FIXNUM_0x4C: + case MsgPackType.POSITIVE_FIXNUM_0x4D: + case MsgPackType.POSITIVE_FIXNUM_0x4E: + case MsgPackType.POSITIVE_FIXNUM_0x4F: + + case MsgPackType.POSITIVE_FIXNUM_0x50: + case MsgPackType.POSITIVE_FIXNUM_0x51: + case MsgPackType.POSITIVE_FIXNUM_0x52: + case MsgPackType.POSITIVE_FIXNUM_0x53: + case MsgPackType.POSITIVE_FIXNUM_0x54: + case MsgPackType.POSITIVE_FIXNUM_0x55: + case MsgPackType.POSITIVE_FIXNUM_0x56: + case MsgPackType.POSITIVE_FIXNUM_0x57: + case MsgPackType.POSITIVE_FIXNUM_0x58: + case MsgPackType.POSITIVE_FIXNUM_0x59: + case MsgPackType.POSITIVE_FIXNUM_0x5A: + case MsgPackType.POSITIVE_FIXNUM_0x5B: + case MsgPackType.POSITIVE_FIXNUM_0x5C: + case MsgPackType.POSITIVE_FIXNUM_0x5D: + case MsgPackType.POSITIVE_FIXNUM_0x5E: + case MsgPackType.POSITIVE_FIXNUM_0x5F: + + case MsgPackType.POSITIVE_FIXNUM_0x60: + case MsgPackType.POSITIVE_FIXNUM_0x61: + case MsgPackType.POSITIVE_FIXNUM_0x62: + case MsgPackType.POSITIVE_FIXNUM_0x63: + case MsgPackType.POSITIVE_FIXNUM_0x64: + case MsgPackType.POSITIVE_FIXNUM_0x65: + case MsgPackType.POSITIVE_FIXNUM_0x66: + case MsgPackType.POSITIVE_FIXNUM_0x67: + case MsgPackType.POSITIVE_FIXNUM_0x68: + case MsgPackType.POSITIVE_FIXNUM_0x69: + case MsgPackType.POSITIVE_FIXNUM_0x6A: + case MsgPackType.POSITIVE_FIXNUM_0x6B: + case MsgPackType.POSITIVE_FIXNUM_0x6C: + case MsgPackType.POSITIVE_FIXNUM_0x6D: + case MsgPackType.POSITIVE_FIXNUM_0x6E: + case MsgPackType.POSITIVE_FIXNUM_0x6F: + + case MsgPackType.POSITIVE_FIXNUM_0x70: + case MsgPackType.POSITIVE_FIXNUM_0x71: + case MsgPackType.POSITIVE_FIXNUM_0x72: + case MsgPackType.POSITIVE_FIXNUM_0x73: + case MsgPackType.POSITIVE_FIXNUM_0x74: + case MsgPackType.POSITIVE_FIXNUM_0x75: + case MsgPackType.POSITIVE_FIXNUM_0x76: + case MsgPackType.POSITIVE_FIXNUM_0x77: + case MsgPackType.POSITIVE_FIXNUM_0x78: + case MsgPackType.POSITIVE_FIXNUM_0x79: + case MsgPackType.POSITIVE_FIXNUM_0x7A: + case MsgPackType.POSITIVE_FIXNUM_0x7B: + case MsgPackType.POSITIVE_FIXNUM_0x7C: + case MsgPackType.POSITIVE_FIXNUM_0x7D: + case MsgPackType.POSITIVE_FIXNUM_0x7E: + case MsgPackType.POSITIVE_FIXNUM_0x7F: + + case MsgPackType.NEGATIVE_FIXNUM: + case MsgPackType.NEGATIVE_FIXNUM_0x01: + case MsgPackType.NEGATIVE_FIXNUM_0x02: + case MsgPackType.NEGATIVE_FIXNUM_0x03: + case MsgPackType.NEGATIVE_FIXNUM_0x04: + case MsgPackType.NEGATIVE_FIXNUM_0x05: + case MsgPackType.NEGATIVE_FIXNUM_0x06: + case MsgPackType.NEGATIVE_FIXNUM_0x07: + case MsgPackType.NEGATIVE_FIXNUM_0x08: + case MsgPackType.NEGATIVE_FIXNUM_0x09: + case MsgPackType.NEGATIVE_FIXNUM_0x0A: + case MsgPackType.NEGATIVE_FIXNUM_0x0B: + case MsgPackType.NEGATIVE_FIXNUM_0x0C: + case MsgPackType.NEGATIVE_FIXNUM_0x0D: + case MsgPackType.NEGATIVE_FIXNUM_0x0E: + case MsgPackType.NEGATIVE_FIXNUM_0x0F: + case MsgPackType.NEGATIVE_FIXNUM_0x10: + case MsgPackType.NEGATIVE_FIXNUM_0x11: + case MsgPackType.NEGATIVE_FIXNUM_0x12: + case MsgPackType.NEGATIVE_FIXNUM_0x13: + case MsgPackType.NEGATIVE_FIXNUM_0x14: + case MsgPackType.NEGATIVE_FIXNUM_0x15: + case MsgPackType.NEGATIVE_FIXNUM_0x16: + case MsgPackType.NEGATIVE_FIXNUM_0x17: + case MsgPackType.NEGATIVE_FIXNUM_0x18: + case MsgPackType.NEGATIVE_FIXNUM_0x19: + case MsgPackType.NEGATIVE_FIXNUM_0x1A: + case MsgPackType.NEGATIVE_FIXNUM_0x1B: + case MsgPackType.NEGATIVE_FIXNUM_0x1C: + case MsgPackType.NEGATIVE_FIXNUM_0x1D: + case MsgPackType.NEGATIVE_FIXNUM_0x1E: + case MsgPackType.NEGATIVE_FIXNUM_0x1F: + return bytes.Advance(1).Take(0); + + case MsgPackType.UINT8: + case MsgPackType.INT8: + return bytes.Advance(1).Take(1); + + case MsgPackType.UINT16: + case MsgPackType.INT16: + return bytes.Advance(1).Take(2); + + case MsgPackType.UINT32: + case MsgPackType.INT32: + case MsgPackType.FLOAT: + return bytes.Advance(1).Take(4); + + case MsgPackType.UINT64: + case MsgPackType.INT64: + case MsgPackType.DOUBLE: + return bytes.Advance(1).Take(8); + + case MsgPackType.FIX_EXT_1: + return bytes.Advance(2).Take(1); + case MsgPackType.FIX_EXT_2: + return bytes.Advance(2).Take(2); + case MsgPackType.FIX_EXT_4: + return bytes.Advance(2).Take(4); + case MsgPackType.FIX_EXT_8: + return bytes.Advance(2).Take(8); + case MsgPackType.FIX_EXT_16: + return bytes.Advance(2).Take(16); + case MsgPackType.EXT8: + { + var count = bytes.Get(1); + return bytes.Advance(1 + 1 + 1).Take(count); + } + case MsgPackType.EXT16: + { + var count = EndianConverter.NetworkByteWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 2 + 1).Take(count); + } + case MsgPackType.EXT32: + { + var count = EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 4 + 1).Take((int)count); + } + default: + throw new ArgumentException("unknown type: " + formatType); + } + } + + static ArraySegment _Parse(ArraySegment bytes, List values, int parentIndex) + { + MsgPackType formatType = GetFormat(bytes); + if (formatType.IsArray()) + { + var index = values.Count; + var offset = bytes.Offset; + values.Add(new MsgPackValue(bytes, parentIndex)); + + uint count; + bytes = GetItemCount(bytes, formatType, out count); + for (var i = 0; i < count; ++i) + { + bytes = _Parse(bytes, values, index); + } + + values[index] = new MsgPackValue( + new ArraySegment(bytes.Array, + offset, bytes.Offset - offset), + parentIndex); + } + else if (formatType.IsMap()) + { + var index = values.Count; + var offset = bytes.Offset; + values.Add(new MsgPackValue(bytes, parentIndex)); + + uint count; + bytes = GetItemCount(bytes, formatType, out count); + for (var i = 0; i < count; ++i) + { + // key + bytes = _Parse(bytes, values, index); + + // value + bytes = _Parse(bytes, values, index); + } + + values[index] = new MsgPackValue( + new ArraySegment(bytes.Array, + offset, bytes.Offset - offset), + parentIndex); + } + else + { + var body = GetBody(bytes, formatType); + var headerSize = body.Offset - bytes.Offset; + var size = headerSize + body.Count; + values.Add(new MsgPackValue(bytes.Take(size), parentIndex)); + bytes = bytes.Advance(size); + } + return bytes; + } + + public static ListTreeNode Parse(ArraySegment bytes) + { + var values = new List(); + _Parse(bytes, values, -1); + return new ListTreeNode(values); + } + } +} diff --git a/Scripts/MsgPack/MsgPackParser.cs.meta b/Scripts/MsgPack/MsgPackParser.cs.meta new file mode 100644 index 000000000..ba4452ea7 --- /dev/null +++ b/Scripts/MsgPack/MsgPackParser.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 96621564d26fc294291143738c163a3d +timeCreated: 1540815282 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/MsgPackType.cs b/Scripts/MsgPack/MsgPackType.cs new file mode 100644 index 000000000..de129d961 --- /dev/null +++ b/Scripts/MsgPack/MsgPackType.cs @@ -0,0 +1,313 @@ +namespace UniJSON +{ + public enum MsgPackType : byte + { + #region POSITIVE_FIXNUM 0x00-0x7F + POSITIVE_FIXNUM = 0x00, + POSITIVE_FIXNUM_0x01 = 0x01, + POSITIVE_FIXNUM_0x02 = 0x02, + POSITIVE_FIXNUM_0x03 = 0x03, + POSITIVE_FIXNUM_0x04 = 0x04, + POSITIVE_FIXNUM_0x05 = 0x05, + POSITIVE_FIXNUM_0x06 = 0x06, + POSITIVE_FIXNUM_0x07 = 0x07, + POSITIVE_FIXNUM_0x08 = 0x08, + POSITIVE_FIXNUM_0x09 = 0x09, + POSITIVE_FIXNUM_0x0A = 0x0A, + POSITIVE_FIXNUM_0x0B = 0x0B, + POSITIVE_FIXNUM_0x0C = 0x0C, + POSITIVE_FIXNUM_0x0D = 0x0D, + POSITIVE_FIXNUM_0x0E = 0x0E, + POSITIVE_FIXNUM_0x0F = 0x0F, + + POSITIVE_FIXNUM_0x10 = 0x10, + POSITIVE_FIXNUM_0x11 = 0x11, + POSITIVE_FIXNUM_0x12 = 0x12, + POSITIVE_FIXNUM_0x13 = 0x13, + POSITIVE_FIXNUM_0x14 = 0x14, + POSITIVE_FIXNUM_0x15 = 0x15, + POSITIVE_FIXNUM_0x16 = 0x16, + POSITIVE_FIXNUM_0x17 = 0x17, + POSITIVE_FIXNUM_0x18 = 0x18, + POSITIVE_FIXNUM_0x19 = 0x19, + POSITIVE_FIXNUM_0x1A = 0x1A, + POSITIVE_FIXNUM_0x1B = 0x1B, + POSITIVE_FIXNUM_0x1C = 0x1C, + POSITIVE_FIXNUM_0x1D = 0x1D, + POSITIVE_FIXNUM_0x1E = 0x1E, + POSITIVE_FIXNUM_0x1F = 0x1F, + + POSITIVE_FIXNUM_0x20 = 0x20, + POSITIVE_FIXNUM_0x21 = 0x21, + POSITIVE_FIXNUM_0x22 = 0x22, + POSITIVE_FIXNUM_0x23 = 0x23, + POSITIVE_FIXNUM_0x24 = 0x24, + POSITIVE_FIXNUM_0x25 = 0x25, + POSITIVE_FIXNUM_0x26 = 0x26, + POSITIVE_FIXNUM_0x27 = 0x27, + POSITIVE_FIXNUM_0x28 = 0x28, + POSITIVE_FIXNUM_0x29 = 0x29, + POSITIVE_FIXNUM_0x2A = 0x2A, + POSITIVE_FIXNUM_0x2B = 0x2B, + POSITIVE_FIXNUM_0x2C = 0x2C, + POSITIVE_FIXNUM_0x2D = 0x2D, + POSITIVE_FIXNUM_0x2E = 0x2E, + POSITIVE_FIXNUM_0x2F = 0x2F, + + POSITIVE_FIXNUM_0x30 = 0x30, + POSITIVE_FIXNUM_0x31 = 0x31, + POSITIVE_FIXNUM_0x32 = 0x32, + POSITIVE_FIXNUM_0x33 = 0x33, + POSITIVE_FIXNUM_0x34 = 0x34, + POSITIVE_FIXNUM_0x35 = 0x35, + POSITIVE_FIXNUM_0x36 = 0x36, + POSITIVE_FIXNUM_0x37 = 0x37, + POSITIVE_FIXNUM_0x38 = 0x38, + POSITIVE_FIXNUM_0x39 = 0x39, + POSITIVE_FIXNUM_0x3A = 0x3A, + POSITIVE_FIXNUM_0x3B = 0x3B, + POSITIVE_FIXNUM_0x3C = 0x3C, + POSITIVE_FIXNUM_0x3D = 0x3D, + POSITIVE_FIXNUM_0x3E = 0x3E, + POSITIVE_FIXNUM_0x3F = 0x3F, + + POSITIVE_FIXNUM_0x40 = 0x40, + POSITIVE_FIXNUM_0x41 = 0x41, + POSITIVE_FIXNUM_0x42 = 0x42, + POSITIVE_FIXNUM_0x43 = 0x43, + POSITIVE_FIXNUM_0x44 = 0x44, + POSITIVE_FIXNUM_0x45 = 0x45, + POSITIVE_FIXNUM_0x46 = 0x46, + POSITIVE_FIXNUM_0x47 = 0x47, + POSITIVE_FIXNUM_0x48 = 0x48, + POSITIVE_FIXNUM_0x49 = 0x49, + POSITIVE_FIXNUM_0x4A = 0x4A, + POSITIVE_FIXNUM_0x4B = 0x4B, + POSITIVE_FIXNUM_0x4C = 0x4C, + POSITIVE_FIXNUM_0x4D = 0x4D, + POSITIVE_FIXNUM_0x4E = 0x4E, + POSITIVE_FIXNUM_0x4F = 0x4F, + + POSITIVE_FIXNUM_0x50 = 0x50, + POSITIVE_FIXNUM_0x51 = 0x51, + POSITIVE_FIXNUM_0x52 = 0x52, + POSITIVE_FIXNUM_0x53 = 0x53, + POSITIVE_FIXNUM_0x54 = 0x54, + POSITIVE_FIXNUM_0x55 = 0x55, + POSITIVE_FIXNUM_0x56 = 0x56, + POSITIVE_FIXNUM_0x57 = 0x57, + POSITIVE_FIXNUM_0x58 = 0x58, + POSITIVE_FIXNUM_0x59 = 0x59, + POSITIVE_FIXNUM_0x5A = 0x5A, + POSITIVE_FIXNUM_0x5B = 0x5B, + POSITIVE_FIXNUM_0x5C = 0x5C, + POSITIVE_FIXNUM_0x5D = 0x5D, + POSITIVE_FIXNUM_0x5E = 0x5E, + POSITIVE_FIXNUM_0x5F = 0x5F, + + POSITIVE_FIXNUM_0x60 = 0x60, + POSITIVE_FIXNUM_0x61 = 0x61, + POSITIVE_FIXNUM_0x62 = 0x62, + POSITIVE_FIXNUM_0x63 = 0x63, + POSITIVE_FIXNUM_0x64 = 0x64, + POSITIVE_FIXNUM_0x65 = 0x65, + POSITIVE_FIXNUM_0x66 = 0x66, + POSITIVE_FIXNUM_0x67 = 0x67, + POSITIVE_FIXNUM_0x68 = 0x68, + POSITIVE_FIXNUM_0x69 = 0x69, + POSITIVE_FIXNUM_0x6A = 0x6A, + POSITIVE_FIXNUM_0x6B = 0x6B, + POSITIVE_FIXNUM_0x6C = 0x6C, + POSITIVE_FIXNUM_0x6D = 0x6D, + POSITIVE_FIXNUM_0x6E = 0x6E, + POSITIVE_FIXNUM_0x6F = 0x6F, + + POSITIVE_FIXNUM_0x70 = 0x70, + POSITIVE_FIXNUM_0x71 = 0x71, + POSITIVE_FIXNUM_0x72 = 0x72, + POSITIVE_FIXNUM_0x73 = 0x73, + POSITIVE_FIXNUM_0x74 = 0x74, + POSITIVE_FIXNUM_0x75 = 0x75, + POSITIVE_FIXNUM_0x76 = 0x76, + POSITIVE_FIXNUM_0x77 = 0x77, + POSITIVE_FIXNUM_0x78 = 0x78, + POSITIVE_FIXNUM_0x79 = 0x79, + POSITIVE_FIXNUM_0x7A = 0x7A, + POSITIVE_FIXNUM_0x7B = 0x7B, + POSITIVE_FIXNUM_0x7C = 0x7C, + POSITIVE_FIXNUM_0x7D = 0x7D, + POSITIVE_FIXNUM_0x7E = 0x7E, + POSITIVE_FIXNUM_0x7F = 0x7F, + #endregion + + #region FIX_MAP 0x80-0x8F + FIX_MAP = 0x80, + FIX_MAP_0x1 = 0x81, + FIX_MAP_0x2 = 0x82, + FIX_MAP_0x3 = 0x83, + FIX_MAP_0x4 = 0x84, + FIX_MAP_0x5 = 0x85, + FIX_MAP_0x6 = 0x86, + FIX_MAP_0x7 = 0x87, + FIX_MAP_0x8 = 0x88, + FIX_MAP_0x9 = 0x89, + FIX_MAP_0xA = 0x8A, + FIX_MAP_0xB = 0x8B, + FIX_MAP_0xC = 0x8C, + FIX_MAP_0xD = 0x8D, + FIX_MAP_0xE = 0x8E, + FIX_MAP_0xF = 0x8F, + #endregion + + #region FIX_ARRAY 0x90-0x9F + FIX_ARRAY = 0x90, + FIX_ARRAY_0x1 = 0x91, + FIX_ARRAY_0x2 = 0x92, + FIX_ARRAY_0x3 = 0x93, + FIX_ARRAY_0x4 = 0x94, + FIX_ARRAY_0x5 = 0x95, + FIX_ARRAY_0x6 = 0x96, + FIX_ARRAY_0x7 = 0x97, + FIX_ARRAY_0x8 = 0x98, + FIX_ARRAY_0x9 = 0x99, + FIX_ARRAY_0xA = 0x9A, + FIX_ARRAY_0xB = 0x9B, + FIX_ARRAY_0xC = 0x9C, + FIX_ARRAY_0xD = 0x9D, + FIX_ARRAY_0xE = 0x9E, + FIX_ARRAY_0xF = 0x9F, + #endregion + + #region FIX_STR 0xA0-0xBF + FIX_STR = 0xA0, + FIX_STR_0x01 = 0xA1, + FIX_STR_0x02 = 0xA2, + FIX_STR_0x03 = 0xA3, + FIX_STR_0x04 = 0xA4, + FIX_STR_0x05 = 0xA5, + FIX_STR_0x06 = 0xA6, + FIX_STR_0x07 = 0xA7, + FIX_STR_0x08 = 0xA8, + FIX_STR_0x09 = 0xA9, + FIX_STR_0x0A = 0xAA, + FIX_STR_0x0B = 0xAB, + FIX_STR_0x0C = 0xAC, + FIX_STR_0x0D = 0xAD, + FIX_STR_0x0E = 0xAE, + FIX_STR_0x0F = 0xAF, + FIX_STR_0x10 = 0xB0, + FIX_STR_0x11 = 0xB1, + FIX_STR_0x12 = 0xB2, + FIX_STR_0x13 = 0xB3, + FIX_STR_0x14 = 0xB4, + FIX_STR_0x15 = 0xB5, + FIX_STR_0x16 = 0xB6, + FIX_STR_0x17 = 0xB7, + FIX_STR_0x18 = 0xB8, + FIX_STR_0x19 = 0xB9, + FIX_STR_0x1A = 0xBA, + FIX_STR_0x1B = 0xBB, + FIX_STR_0x1C = 0xBC, + FIX_STR_0x1D = 0xBD, + FIX_STR_0x1E = 0xBE, + FIX_STR_0x1F = 0xBF, + #endregion + + NIL = 0xC0, + NEVER_USED = 0xC1, + FALSE = 0xC2, + TRUE = 0xC3, + + BIN8 = 0xC4, + BIN16 = 0xC5, + BIN32 = 0xC6, + + EXT8 = 0xC7, + EXT16 = 0xC8, + EXT32 = 0xC9, + + FLOAT = 0xCA, + DOUBLE = 0xCB, + UINT8 = 0xCC, + UINT16 = 0xCD, + UINT32 = 0xCE, + UINT64 = 0xCF, + INT8 = 0xD0, + INT16 = 0xD1, + INT32 = 0xD2, + INT64 = 0xD3, + + FIX_EXT_1 = 0xD4, + FIX_EXT_2 = 0xD5, + FIX_EXT_4 = 0xD6, + FIX_EXT_8 = 0xD7, + FIX_EXT_16 = 0xD8, + + STR8 = 0xD9, + STR16 = 0xDA, + STR32 = 0xDB, + + ARRAY16 = 0xDC, + ARRAY32 = 0xDD, + MAP16 = 0xDE, + MAP32 = 0xDF, + + #region NEGATIVE_FIXNUM 0xE0-0xFF + NEGATIVE_FIXNUM = 0xE0, // 1110 0000 = -32 + NEGATIVE_FIXNUM_0x1F = 0xE1, // -31 + NEGATIVE_FIXNUM_0x1E = 0xE2, + NEGATIVE_FIXNUM_0x1D = 0xE3, + NEGATIVE_FIXNUM_0x1C = 0xE4, + NEGATIVE_FIXNUM_0x1B = 0xE5, + NEGATIVE_FIXNUM_0x1A = 0xE6, + NEGATIVE_FIXNUM_0x19 = 0xE7, + NEGATIVE_FIXNUM_0x18 = 0xE8, + NEGATIVE_FIXNUM_0x17 = 0xE9, + NEGATIVE_FIXNUM_0x16 = 0xEA, + NEGATIVE_FIXNUM_0x15 = 0xEB, + NEGATIVE_FIXNUM_0x14 = 0xEC, + NEGATIVE_FIXNUM_0x13 = 0xED, + NEGATIVE_FIXNUM_0x12 = 0xEE, + NEGATIVE_FIXNUM_0x11 = 0xEF, + NEGATIVE_FIXNUM_0x10 = 0xF0, + NEGATIVE_FIXNUM_0x0F = 0xF1, + NEGATIVE_FIXNUM_0x0E = 0xF2, + NEGATIVE_FIXNUM_0x0D = 0xF3, + NEGATIVE_FIXNUM_0x0C = 0xF4, + NEGATIVE_FIXNUM_0x0B = 0xF5, + NEGATIVE_FIXNUM_0x0A = 0xF6, + NEGATIVE_FIXNUM_0x09 = 0xF7, + NEGATIVE_FIXNUM_0x08 = 0xF8, + NEGATIVE_FIXNUM_0x07 = 0xF9, + NEGATIVE_FIXNUM_0x06 = 0xFA, + NEGATIVE_FIXNUM_0x05 = 0xFB, + NEGATIVE_FIXNUM_0x04 = 0xFC, + NEGATIVE_FIXNUM_0x03 = 0xFD, + NEGATIVE_FIXNUM_0x02 = 0xFE, + NEGATIVE_FIXNUM_0x01 = 0xFF, // -1 + #endregion + } + + public enum ExtType : byte + { + UNKNOWN = 0x00, + + UINT16_BE = 0x01, + UINT32_BE = 0x02, + UINT64_BE = 0x03, + INT16_BE = 0x04, + INT32_BE = 0x05, + INT64_BE = 0x06, + SINGLE_BE = 0x07, + DOUBLE_BE = 0x08, + + UINT16_LE = 0x09, + UINT32_LE = 0x0A, + UINT64_LE = 0x0B, + INT16_LE = 0x0C, + INT32_LE = 0x0D, + INT64_LE = 0x0E, + SINGLE_LE = 0x0F, + DOUBLE_LE = 0x10, + } +} diff --git a/Scripts/MsgPack/MsgPackType.cs.meta b/Scripts/MsgPack/MsgPackType.cs.meta new file mode 100644 index 000000000..702f717e8 --- /dev/null +++ b/Scripts/MsgPack/MsgPackType.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4c6d91a562e590e438f0baa988389d61 +timeCreated: 1540814648 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/MsgPackTypeExtensions.cs b/Scripts/MsgPack/MsgPackTypeExtensions.cs new file mode 100644 index 000000000..cfd61b192 --- /dev/null +++ b/Scripts/MsgPack/MsgPackTypeExtensions.cs @@ -0,0 +1,341 @@ +namespace UniJSON +{ + public static class MsgPackTypeExtensions + { + public static bool IsArray(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.FIX_ARRAY: + case MsgPackType.FIX_ARRAY_0x1: + case MsgPackType.FIX_ARRAY_0x2: + case MsgPackType.FIX_ARRAY_0x3: + case MsgPackType.FIX_ARRAY_0x4: + case MsgPackType.FIX_ARRAY_0x5: + case MsgPackType.FIX_ARRAY_0x6: + case MsgPackType.FIX_ARRAY_0x7: + case MsgPackType.FIX_ARRAY_0x8: + case MsgPackType.FIX_ARRAY_0x9: + case MsgPackType.FIX_ARRAY_0xA: + case MsgPackType.FIX_ARRAY_0xB: + case MsgPackType.FIX_ARRAY_0xC: + case MsgPackType.FIX_ARRAY_0xD: + case MsgPackType.FIX_ARRAY_0xE: + case MsgPackType.FIX_ARRAY_0xF: + case MsgPackType.ARRAY16: + case MsgPackType.ARRAY32: + return true; + + default: + return false; + } + } + + public static bool IsMap(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.FIX_MAP: + case MsgPackType.FIX_MAP_0x1: + case MsgPackType.FIX_MAP_0x2: + case MsgPackType.FIX_MAP_0x3: + case MsgPackType.FIX_MAP_0x4: + case MsgPackType.FIX_MAP_0x5: + case MsgPackType.FIX_MAP_0x6: + case MsgPackType.FIX_MAP_0x7: + case MsgPackType.FIX_MAP_0x8: + case MsgPackType.FIX_MAP_0x9: + case MsgPackType.FIX_MAP_0xA: + case MsgPackType.FIX_MAP_0xB: + case MsgPackType.FIX_MAP_0xC: + case MsgPackType.FIX_MAP_0xD: + case MsgPackType.FIX_MAP_0xE: + case MsgPackType.FIX_MAP_0xF: + case MsgPackType.MAP16: + case MsgPackType.MAP32: + return true; + + default: + return false; + } + } + + public static bool IsInteger(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.POSITIVE_FIXNUM: + case MsgPackType.POSITIVE_FIXNUM_0x01: + case MsgPackType.POSITIVE_FIXNUM_0x02: + case MsgPackType.POSITIVE_FIXNUM_0x03: + case MsgPackType.POSITIVE_FIXNUM_0x04: + case MsgPackType.POSITIVE_FIXNUM_0x05: + case MsgPackType.POSITIVE_FIXNUM_0x06: + case MsgPackType.POSITIVE_FIXNUM_0x07: + case MsgPackType.POSITIVE_FIXNUM_0x08: + case MsgPackType.POSITIVE_FIXNUM_0x09: + case MsgPackType.POSITIVE_FIXNUM_0x0A: + case MsgPackType.POSITIVE_FIXNUM_0x0B: + case MsgPackType.POSITIVE_FIXNUM_0x0C: + case MsgPackType.POSITIVE_FIXNUM_0x0D: + case MsgPackType.POSITIVE_FIXNUM_0x0E: + case MsgPackType.POSITIVE_FIXNUM_0x0F: + + case MsgPackType.POSITIVE_FIXNUM_0x10: + case MsgPackType.POSITIVE_FIXNUM_0x11: + case MsgPackType.POSITIVE_FIXNUM_0x12: + case MsgPackType.POSITIVE_FIXNUM_0x13: + case MsgPackType.POSITIVE_FIXNUM_0x14: + case MsgPackType.POSITIVE_FIXNUM_0x15: + case MsgPackType.POSITIVE_FIXNUM_0x16: + case MsgPackType.POSITIVE_FIXNUM_0x17: + case MsgPackType.POSITIVE_FIXNUM_0x18: + case MsgPackType.POSITIVE_FIXNUM_0x19: + case MsgPackType.POSITIVE_FIXNUM_0x1A: + case MsgPackType.POSITIVE_FIXNUM_0x1B: + case MsgPackType.POSITIVE_FIXNUM_0x1C: + case MsgPackType.POSITIVE_FIXNUM_0x1D: + case MsgPackType.POSITIVE_FIXNUM_0x1E: + case MsgPackType.POSITIVE_FIXNUM_0x1F: + + case MsgPackType.POSITIVE_FIXNUM_0x20: + case MsgPackType.POSITIVE_FIXNUM_0x21: + case MsgPackType.POSITIVE_FIXNUM_0x22: + case MsgPackType.POSITIVE_FIXNUM_0x23: + case MsgPackType.POSITIVE_FIXNUM_0x24: + case MsgPackType.POSITIVE_FIXNUM_0x25: + case MsgPackType.POSITIVE_FIXNUM_0x26: + case MsgPackType.POSITIVE_FIXNUM_0x27: + case MsgPackType.POSITIVE_FIXNUM_0x28: + case MsgPackType.POSITIVE_FIXNUM_0x29: + case MsgPackType.POSITIVE_FIXNUM_0x2A: + case MsgPackType.POSITIVE_FIXNUM_0x2B: + case MsgPackType.POSITIVE_FIXNUM_0x2C: + case MsgPackType.POSITIVE_FIXNUM_0x2D: + case MsgPackType.POSITIVE_FIXNUM_0x2E: + case MsgPackType.POSITIVE_FIXNUM_0x2F: + + case MsgPackType.POSITIVE_FIXNUM_0x30: + case MsgPackType.POSITIVE_FIXNUM_0x31: + case MsgPackType.POSITIVE_FIXNUM_0x32: + case MsgPackType.POSITIVE_FIXNUM_0x33: + case MsgPackType.POSITIVE_FIXNUM_0x34: + case MsgPackType.POSITIVE_FIXNUM_0x35: + case MsgPackType.POSITIVE_FIXNUM_0x36: + case MsgPackType.POSITIVE_FIXNUM_0x37: + case MsgPackType.POSITIVE_FIXNUM_0x38: + case MsgPackType.POSITIVE_FIXNUM_0x39: + case MsgPackType.POSITIVE_FIXNUM_0x3A: + case MsgPackType.POSITIVE_FIXNUM_0x3B: + case MsgPackType.POSITIVE_FIXNUM_0x3C: + case MsgPackType.POSITIVE_FIXNUM_0x3D: + case MsgPackType.POSITIVE_FIXNUM_0x3E: + case MsgPackType.POSITIVE_FIXNUM_0x3F: + + case MsgPackType.POSITIVE_FIXNUM_0x40: + case MsgPackType.POSITIVE_FIXNUM_0x41: + case MsgPackType.POSITIVE_FIXNUM_0x42: + case MsgPackType.POSITIVE_FIXNUM_0x43: + case MsgPackType.POSITIVE_FIXNUM_0x44: + case MsgPackType.POSITIVE_FIXNUM_0x45: + case MsgPackType.POSITIVE_FIXNUM_0x46: + case MsgPackType.POSITIVE_FIXNUM_0x47: + case MsgPackType.POSITIVE_FIXNUM_0x48: + case MsgPackType.POSITIVE_FIXNUM_0x49: + case MsgPackType.POSITIVE_FIXNUM_0x4A: + case MsgPackType.POSITIVE_FIXNUM_0x4B: + case MsgPackType.POSITIVE_FIXNUM_0x4C: + case MsgPackType.POSITIVE_FIXNUM_0x4D: + case MsgPackType.POSITIVE_FIXNUM_0x4E: + case MsgPackType.POSITIVE_FIXNUM_0x4F: + + case MsgPackType.POSITIVE_FIXNUM_0x50: + case MsgPackType.POSITIVE_FIXNUM_0x51: + case MsgPackType.POSITIVE_FIXNUM_0x52: + case MsgPackType.POSITIVE_FIXNUM_0x53: + case MsgPackType.POSITIVE_FIXNUM_0x54: + case MsgPackType.POSITIVE_FIXNUM_0x55: + case MsgPackType.POSITIVE_FIXNUM_0x56: + case MsgPackType.POSITIVE_FIXNUM_0x57: + case MsgPackType.POSITIVE_FIXNUM_0x58: + case MsgPackType.POSITIVE_FIXNUM_0x59: + case MsgPackType.POSITIVE_FIXNUM_0x5A: + case MsgPackType.POSITIVE_FIXNUM_0x5B: + case MsgPackType.POSITIVE_FIXNUM_0x5C: + case MsgPackType.POSITIVE_FIXNUM_0x5D: + case MsgPackType.POSITIVE_FIXNUM_0x5E: + case MsgPackType.POSITIVE_FIXNUM_0x5F: + + case MsgPackType.POSITIVE_FIXNUM_0x60: + case MsgPackType.POSITIVE_FIXNUM_0x61: + case MsgPackType.POSITIVE_FIXNUM_0x62: + case MsgPackType.POSITIVE_FIXNUM_0x63: + case MsgPackType.POSITIVE_FIXNUM_0x64: + case MsgPackType.POSITIVE_FIXNUM_0x65: + case MsgPackType.POSITIVE_FIXNUM_0x66: + case MsgPackType.POSITIVE_FIXNUM_0x67: + case MsgPackType.POSITIVE_FIXNUM_0x68: + case MsgPackType.POSITIVE_FIXNUM_0x69: + case MsgPackType.POSITIVE_FIXNUM_0x6A: + case MsgPackType.POSITIVE_FIXNUM_0x6B: + case MsgPackType.POSITIVE_FIXNUM_0x6C: + case MsgPackType.POSITIVE_FIXNUM_0x6D: + case MsgPackType.POSITIVE_FIXNUM_0x6E: + case MsgPackType.POSITIVE_FIXNUM_0x6F: + + case MsgPackType.POSITIVE_FIXNUM_0x70: + case MsgPackType.POSITIVE_FIXNUM_0x71: + case MsgPackType.POSITIVE_FIXNUM_0x72: + case MsgPackType.POSITIVE_FIXNUM_0x73: + case MsgPackType.POSITIVE_FIXNUM_0x74: + case MsgPackType.POSITIVE_FIXNUM_0x75: + case MsgPackType.POSITIVE_FIXNUM_0x76: + case MsgPackType.POSITIVE_FIXNUM_0x77: + case MsgPackType.POSITIVE_FIXNUM_0x78: + case MsgPackType.POSITIVE_FIXNUM_0x79: + case MsgPackType.POSITIVE_FIXNUM_0x7A: + case MsgPackType.POSITIVE_FIXNUM_0x7B: + case MsgPackType.POSITIVE_FIXNUM_0x7C: + case MsgPackType.POSITIVE_FIXNUM_0x7D: + case MsgPackType.POSITIVE_FIXNUM_0x7E: + case MsgPackType.POSITIVE_FIXNUM_0x7F: + + case MsgPackType.NEGATIVE_FIXNUM: + case MsgPackType.NEGATIVE_FIXNUM_0x01: + case MsgPackType.NEGATIVE_FIXNUM_0x02: + case MsgPackType.NEGATIVE_FIXNUM_0x03: + case MsgPackType.NEGATIVE_FIXNUM_0x04: + case MsgPackType.NEGATIVE_FIXNUM_0x05: + case MsgPackType.NEGATIVE_FIXNUM_0x06: + case MsgPackType.NEGATIVE_FIXNUM_0x07: + case MsgPackType.NEGATIVE_FIXNUM_0x08: + case MsgPackType.NEGATIVE_FIXNUM_0x09: + case MsgPackType.NEGATIVE_FIXNUM_0x0A: + case MsgPackType.NEGATIVE_FIXNUM_0x0B: + case MsgPackType.NEGATIVE_FIXNUM_0x0C: + case MsgPackType.NEGATIVE_FIXNUM_0x0D: + case MsgPackType.NEGATIVE_FIXNUM_0x0E: + case MsgPackType.NEGATIVE_FIXNUM_0x0F: + case MsgPackType.NEGATIVE_FIXNUM_0x10: + case MsgPackType.NEGATIVE_FIXNUM_0x11: + case MsgPackType.NEGATIVE_FIXNUM_0x12: + case MsgPackType.NEGATIVE_FIXNUM_0x13: + case MsgPackType.NEGATIVE_FIXNUM_0x14: + case MsgPackType.NEGATIVE_FIXNUM_0x15: + case MsgPackType.NEGATIVE_FIXNUM_0x16: + case MsgPackType.NEGATIVE_FIXNUM_0x17: + case MsgPackType.NEGATIVE_FIXNUM_0x18: + case MsgPackType.NEGATIVE_FIXNUM_0x19: + case MsgPackType.NEGATIVE_FIXNUM_0x1A: + case MsgPackType.NEGATIVE_FIXNUM_0x1B: + case MsgPackType.NEGATIVE_FIXNUM_0x1C: + case MsgPackType.NEGATIVE_FIXNUM_0x1D: + case MsgPackType.NEGATIVE_FIXNUM_0x1E: + case MsgPackType.NEGATIVE_FIXNUM_0x1F: + + case MsgPackType.INT8: + case MsgPackType.INT16: + case MsgPackType.INT32: + case MsgPackType.INT64: + case MsgPackType.UINT8: + case MsgPackType.UINT16: + case MsgPackType.UINT32: + case MsgPackType.UINT64: + return true; + + default: + return false; + } + } + + public static bool IsFloat(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.FLOAT: + case MsgPackType.DOUBLE: + return true; + + default: + return false; + } + } + + public static bool IsString(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.FIX_STR: + case MsgPackType.FIX_STR_0x01: + case MsgPackType.FIX_STR_0x02: + case MsgPackType.FIX_STR_0x03: + case MsgPackType.FIX_STR_0x04: + case MsgPackType.FIX_STR_0x05: + case MsgPackType.FIX_STR_0x06: + case MsgPackType.FIX_STR_0x07: + case MsgPackType.FIX_STR_0x08: + case MsgPackType.FIX_STR_0x09: + case MsgPackType.FIX_STR_0x0A: + case MsgPackType.FIX_STR_0x0B: + case MsgPackType.FIX_STR_0x0C: + case MsgPackType.FIX_STR_0x0D: + case MsgPackType.FIX_STR_0x0E: + case MsgPackType.FIX_STR_0x0F: + case MsgPackType.FIX_STR_0x10: + case MsgPackType.FIX_STR_0x11: + case MsgPackType.FIX_STR_0x12: + case MsgPackType.FIX_STR_0x13: + case MsgPackType.FIX_STR_0x14: + case MsgPackType.FIX_STR_0x15: + case MsgPackType.FIX_STR_0x16: + case MsgPackType.FIX_STR_0x17: + case MsgPackType.FIX_STR_0x18: + case MsgPackType.FIX_STR_0x19: + case MsgPackType.FIX_STR_0x1A: + case MsgPackType.FIX_STR_0x1B: + case MsgPackType.FIX_STR_0x1C: + case MsgPackType.FIX_STR_0x1D: + case MsgPackType.FIX_STR_0x1E: + case MsgPackType.FIX_STR_0x1F: + case MsgPackType.STR8: + case MsgPackType.STR16: + case MsgPackType.STR32: + return true; + } + return false; + } + + public static bool IsExt(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.FIX_EXT_1: + case MsgPackType.FIX_EXT_2: + case MsgPackType.FIX_EXT_4: + case MsgPackType.FIX_EXT_8: + case MsgPackType.FIX_EXT_16: + case MsgPackType.EXT8: + case MsgPackType.EXT16: + case MsgPackType.EXT32: + return true; + + default: + return false; + } + } + + public static bool IsBinary(this MsgPackType formatType) + { + switch (formatType) + { + case MsgPackType.BIN8: + case MsgPackType.BIN16: + case MsgPackType.BIN32: + return true; + + default: + return false; + } + } + } +} diff --git a/Scripts/MsgPack/MsgPackTypeExtensions.cs.meta b/Scripts/MsgPack/MsgPackTypeExtensions.cs.meta new file mode 100644 index 000000000..4c4ef420a --- /dev/null +++ b/Scripts/MsgPack/MsgPackTypeExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6e803181a063cd940b8272f45497b506 +timeCreated: 1540898737 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/MsgPack/MsgPackValue.cs b/Scripts/MsgPack/MsgPackValue.cs new file mode 100644 index 000000000..97080650e --- /dev/null +++ b/Scripts/MsgPack/MsgPackValue.cs @@ -0,0 +1,753 @@ +using System; +using System.Text; + +namespace UniJSON +{ + public struct MsgPackValue: IListTreeItem, IValue + { + public int ParentIndex + { + get; + private set; + } + + public ArraySegment Bytes + { + get; + private set; + } + + public MsgPackType Format + { + get + { + return (MsgPackType)Bytes.Get(0); + } + } + + public ValueNodeType ValueType + { + get + { + switch (Format) + { + case MsgPackType.NIL: + return ValueNodeType.Null; + + case MsgPackType.TRUE: + case MsgPackType.FALSE: + return ValueNodeType.Boolean; + + default: + if (Format.IsArray()) + { + return ValueNodeType.Array; + } + else if (Format.IsMap()) + { + return ValueNodeType.Object; + } + else if (Format.IsInteger()) + { + return ValueNodeType.Integer; + } + else if (Format.IsFloat()) + { + return ValueNodeType.Number; + } + else if (Format.IsString()) + { + return ValueNodeType.String; + } + else if (Format.IsBinary()) + { + return ValueNodeType.Binary; + } + else + { + throw new NotImplementedException(); + } + } + } + } + + public MsgPackValue(ArraySegment segment, int parentIndex) : this() + { + Bytes = segment; + ParentIndex = parentIndex; + } + + public MsgPackValue New(ArraySegment bytes, ValueNodeType valueType, int parentIndex) + { + throw new NotImplementedException(); + } + + public MsgPackValue Key(Utf8String key, int parentIndex) + { + throw new NotImplementedException(); + } + + /// + /// ArrayとMap以外のタイプのペイロードを得る + /// + /// + public ArraySegment GetBody() + { + var bytes = Bytes; + var formatType = Format; + switch (formatType) + { + case MsgPackType.FIX_STR: return bytes.Advance(1).Take(0); + case MsgPackType.FIX_STR_0x01: return bytes.Advance(1).Take(1); + case MsgPackType.FIX_STR_0x02: return bytes.Advance(1).Take(2); + case MsgPackType.FIX_STR_0x03: return bytes.Advance(1).Take(3); + case MsgPackType.FIX_STR_0x04: return bytes.Advance(1).Take(4); + case MsgPackType.FIX_STR_0x05: return bytes.Advance(1).Take(5); + case MsgPackType.FIX_STR_0x06: return bytes.Advance(1).Take(6); + case MsgPackType.FIX_STR_0x07: return bytes.Advance(1).Take(7); + case MsgPackType.FIX_STR_0x08: return bytes.Advance(1).Take(8); + case MsgPackType.FIX_STR_0x09: return bytes.Advance(1).Take(9); + case MsgPackType.FIX_STR_0x0A: return bytes.Advance(1).Take(10); + case MsgPackType.FIX_STR_0x0B: return bytes.Advance(1).Take(11); + case MsgPackType.FIX_STR_0x0C: return bytes.Advance(1).Take(12); + case MsgPackType.FIX_STR_0x0D: return bytes.Advance(1).Take(13); + case MsgPackType.FIX_STR_0x0E: return bytes.Advance(1).Take(14); + case MsgPackType.FIX_STR_0x0F: return bytes.Advance(1).Take(15); + + case MsgPackType.FIX_STR_0x10: return bytes.Advance(1).Take(16); + case MsgPackType.FIX_STR_0x11: return bytes.Advance(1).Take(17); + case MsgPackType.FIX_STR_0x12: return bytes.Advance(1).Take(18); + case MsgPackType.FIX_STR_0x13: return bytes.Advance(1).Take(19); + case MsgPackType.FIX_STR_0x14: return bytes.Advance(1).Take(20); + case MsgPackType.FIX_STR_0x15: return bytes.Advance(1).Take(21); + case MsgPackType.FIX_STR_0x16: return bytes.Advance(1).Take(22); + case MsgPackType.FIX_STR_0x17: return bytes.Advance(1).Take(23); + case MsgPackType.FIX_STR_0x18: return bytes.Advance(1).Take(24); + case MsgPackType.FIX_STR_0x19: return bytes.Advance(1).Take(25); + case MsgPackType.FIX_STR_0x1A: return bytes.Advance(1).Take(26); + case MsgPackType.FIX_STR_0x1B: return bytes.Advance(1).Take(27); + case MsgPackType.FIX_STR_0x1C: return bytes.Advance(1).Take(28); + case MsgPackType.FIX_STR_0x1D: return bytes.Advance(1).Take(29); + case MsgPackType.FIX_STR_0x1E: return bytes.Advance(1).Take(30); + case MsgPackType.FIX_STR_0x1F: return bytes.Advance(1).Take(31); + + case MsgPackType.STR8: + case MsgPackType.BIN8: + { + var count = bytes.Get(1); + return bytes.Advance(1 + 1).Take(count); + } + + case MsgPackType.STR16: + case MsgPackType.BIN16: + { + var count = EndianConverter.NetworkByteWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 2).Take(count); + } + + case MsgPackType.STR32: + case MsgPackType.BIN32: + { + var count = EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 4).Take((int)count); + } + + case MsgPackType.NIL: + case MsgPackType.TRUE: + case MsgPackType.FALSE: + case MsgPackType.POSITIVE_FIXNUM: + case MsgPackType.POSITIVE_FIXNUM_0x01: + case MsgPackType.POSITIVE_FIXNUM_0x02: + case MsgPackType.POSITIVE_FIXNUM_0x03: + case MsgPackType.POSITIVE_FIXNUM_0x04: + case MsgPackType.POSITIVE_FIXNUM_0x05: + case MsgPackType.POSITIVE_FIXNUM_0x06: + case MsgPackType.POSITIVE_FIXNUM_0x07: + case MsgPackType.POSITIVE_FIXNUM_0x08: + case MsgPackType.POSITIVE_FIXNUM_0x09: + case MsgPackType.POSITIVE_FIXNUM_0x0A: + case MsgPackType.POSITIVE_FIXNUM_0x0B: + case MsgPackType.POSITIVE_FIXNUM_0x0C: + case MsgPackType.POSITIVE_FIXNUM_0x0D: + case MsgPackType.POSITIVE_FIXNUM_0x0E: + case MsgPackType.POSITIVE_FIXNUM_0x0F: + + case MsgPackType.POSITIVE_FIXNUM_0x10: + case MsgPackType.POSITIVE_FIXNUM_0x11: + case MsgPackType.POSITIVE_FIXNUM_0x12: + case MsgPackType.POSITIVE_FIXNUM_0x13: + case MsgPackType.POSITIVE_FIXNUM_0x14: + case MsgPackType.POSITIVE_FIXNUM_0x15: + case MsgPackType.POSITIVE_FIXNUM_0x16: + case MsgPackType.POSITIVE_FIXNUM_0x17: + case MsgPackType.POSITIVE_FIXNUM_0x18: + case MsgPackType.POSITIVE_FIXNUM_0x19: + case MsgPackType.POSITIVE_FIXNUM_0x1A: + case MsgPackType.POSITIVE_FIXNUM_0x1B: + case MsgPackType.POSITIVE_FIXNUM_0x1C: + case MsgPackType.POSITIVE_FIXNUM_0x1D: + case MsgPackType.POSITIVE_FIXNUM_0x1E: + case MsgPackType.POSITIVE_FIXNUM_0x1F: + + case MsgPackType.POSITIVE_FIXNUM_0x20: + case MsgPackType.POSITIVE_FIXNUM_0x21: + case MsgPackType.POSITIVE_FIXNUM_0x22: + case MsgPackType.POSITIVE_FIXNUM_0x23: + case MsgPackType.POSITIVE_FIXNUM_0x24: + case MsgPackType.POSITIVE_FIXNUM_0x25: + case MsgPackType.POSITIVE_FIXNUM_0x26: + case MsgPackType.POSITIVE_FIXNUM_0x27: + case MsgPackType.POSITIVE_FIXNUM_0x28: + case MsgPackType.POSITIVE_FIXNUM_0x29: + case MsgPackType.POSITIVE_FIXNUM_0x2A: + case MsgPackType.POSITIVE_FIXNUM_0x2B: + case MsgPackType.POSITIVE_FIXNUM_0x2C: + case MsgPackType.POSITIVE_FIXNUM_0x2D: + case MsgPackType.POSITIVE_FIXNUM_0x2E: + case MsgPackType.POSITIVE_FIXNUM_0x2F: + + case MsgPackType.POSITIVE_FIXNUM_0x30: + case MsgPackType.POSITIVE_FIXNUM_0x31: + case MsgPackType.POSITIVE_FIXNUM_0x32: + case MsgPackType.POSITIVE_FIXNUM_0x33: + case MsgPackType.POSITIVE_FIXNUM_0x34: + case MsgPackType.POSITIVE_FIXNUM_0x35: + case MsgPackType.POSITIVE_FIXNUM_0x36: + case MsgPackType.POSITIVE_FIXNUM_0x37: + case MsgPackType.POSITIVE_FIXNUM_0x38: + case MsgPackType.POSITIVE_FIXNUM_0x39: + case MsgPackType.POSITIVE_FIXNUM_0x3A: + case MsgPackType.POSITIVE_FIXNUM_0x3B: + case MsgPackType.POSITIVE_FIXNUM_0x3C: + case MsgPackType.POSITIVE_FIXNUM_0x3D: + case MsgPackType.POSITIVE_FIXNUM_0x3E: + case MsgPackType.POSITIVE_FIXNUM_0x3F: + + case MsgPackType.POSITIVE_FIXNUM_0x40: + case MsgPackType.POSITIVE_FIXNUM_0x41: + case MsgPackType.POSITIVE_FIXNUM_0x42: + case MsgPackType.POSITIVE_FIXNUM_0x43: + case MsgPackType.POSITIVE_FIXNUM_0x44: + case MsgPackType.POSITIVE_FIXNUM_0x45: + case MsgPackType.POSITIVE_FIXNUM_0x46: + case MsgPackType.POSITIVE_FIXNUM_0x47: + case MsgPackType.POSITIVE_FIXNUM_0x48: + case MsgPackType.POSITIVE_FIXNUM_0x49: + case MsgPackType.POSITIVE_FIXNUM_0x4A: + case MsgPackType.POSITIVE_FIXNUM_0x4B: + case MsgPackType.POSITIVE_FIXNUM_0x4C: + case MsgPackType.POSITIVE_FIXNUM_0x4D: + case MsgPackType.POSITIVE_FIXNUM_0x4E: + case MsgPackType.POSITIVE_FIXNUM_0x4F: + + case MsgPackType.POSITIVE_FIXNUM_0x50: + case MsgPackType.POSITIVE_FIXNUM_0x51: + case MsgPackType.POSITIVE_FIXNUM_0x52: + case MsgPackType.POSITIVE_FIXNUM_0x53: + case MsgPackType.POSITIVE_FIXNUM_0x54: + case MsgPackType.POSITIVE_FIXNUM_0x55: + case MsgPackType.POSITIVE_FIXNUM_0x56: + case MsgPackType.POSITIVE_FIXNUM_0x57: + case MsgPackType.POSITIVE_FIXNUM_0x58: + case MsgPackType.POSITIVE_FIXNUM_0x59: + case MsgPackType.POSITIVE_FIXNUM_0x5A: + case MsgPackType.POSITIVE_FIXNUM_0x5B: + case MsgPackType.POSITIVE_FIXNUM_0x5C: + case MsgPackType.POSITIVE_FIXNUM_0x5D: + case MsgPackType.POSITIVE_FIXNUM_0x5E: + case MsgPackType.POSITIVE_FIXNUM_0x5F: + + case MsgPackType.POSITIVE_FIXNUM_0x60: + case MsgPackType.POSITIVE_FIXNUM_0x61: + case MsgPackType.POSITIVE_FIXNUM_0x62: + case MsgPackType.POSITIVE_FIXNUM_0x63: + case MsgPackType.POSITIVE_FIXNUM_0x64: + case MsgPackType.POSITIVE_FIXNUM_0x65: + case MsgPackType.POSITIVE_FIXNUM_0x66: + case MsgPackType.POSITIVE_FIXNUM_0x67: + case MsgPackType.POSITIVE_FIXNUM_0x68: + case MsgPackType.POSITIVE_FIXNUM_0x69: + case MsgPackType.POSITIVE_FIXNUM_0x6A: + case MsgPackType.POSITIVE_FIXNUM_0x6B: + case MsgPackType.POSITIVE_FIXNUM_0x6C: + case MsgPackType.POSITIVE_FIXNUM_0x6D: + case MsgPackType.POSITIVE_FIXNUM_0x6E: + case MsgPackType.POSITIVE_FIXNUM_0x6F: + + case MsgPackType.POSITIVE_FIXNUM_0x70: + case MsgPackType.POSITIVE_FIXNUM_0x71: + case MsgPackType.POSITIVE_FIXNUM_0x72: + case MsgPackType.POSITIVE_FIXNUM_0x73: + case MsgPackType.POSITIVE_FIXNUM_0x74: + case MsgPackType.POSITIVE_FIXNUM_0x75: + case MsgPackType.POSITIVE_FIXNUM_0x76: + case MsgPackType.POSITIVE_FIXNUM_0x77: + case MsgPackType.POSITIVE_FIXNUM_0x78: + case MsgPackType.POSITIVE_FIXNUM_0x79: + case MsgPackType.POSITIVE_FIXNUM_0x7A: + case MsgPackType.POSITIVE_FIXNUM_0x7B: + case MsgPackType.POSITIVE_FIXNUM_0x7C: + case MsgPackType.POSITIVE_FIXNUM_0x7D: + case MsgPackType.POSITIVE_FIXNUM_0x7E: + case MsgPackType.POSITIVE_FIXNUM_0x7F: + + case MsgPackType.NEGATIVE_FIXNUM: + case MsgPackType.NEGATIVE_FIXNUM_0x01: + case MsgPackType.NEGATIVE_FIXNUM_0x02: + case MsgPackType.NEGATIVE_FIXNUM_0x03: + case MsgPackType.NEGATIVE_FIXNUM_0x04: + case MsgPackType.NEGATIVE_FIXNUM_0x05: + case MsgPackType.NEGATIVE_FIXNUM_0x06: + case MsgPackType.NEGATIVE_FIXNUM_0x07: + case MsgPackType.NEGATIVE_FIXNUM_0x08: + case MsgPackType.NEGATIVE_FIXNUM_0x09: + case MsgPackType.NEGATIVE_FIXNUM_0x0A: + case MsgPackType.NEGATIVE_FIXNUM_0x0B: + case MsgPackType.NEGATIVE_FIXNUM_0x0C: + case MsgPackType.NEGATIVE_FIXNUM_0x0D: + case MsgPackType.NEGATIVE_FIXNUM_0x0E: + case MsgPackType.NEGATIVE_FIXNUM_0x0F: + case MsgPackType.NEGATIVE_FIXNUM_0x10: + case MsgPackType.NEGATIVE_FIXNUM_0x11: + case MsgPackType.NEGATIVE_FIXNUM_0x12: + case MsgPackType.NEGATIVE_FIXNUM_0x13: + case MsgPackType.NEGATIVE_FIXNUM_0x14: + case MsgPackType.NEGATIVE_FIXNUM_0x15: + case MsgPackType.NEGATIVE_FIXNUM_0x16: + case MsgPackType.NEGATIVE_FIXNUM_0x17: + case MsgPackType.NEGATIVE_FIXNUM_0x18: + case MsgPackType.NEGATIVE_FIXNUM_0x19: + case MsgPackType.NEGATIVE_FIXNUM_0x1A: + case MsgPackType.NEGATIVE_FIXNUM_0x1B: + case MsgPackType.NEGATIVE_FIXNUM_0x1C: + case MsgPackType.NEGATIVE_FIXNUM_0x1D: + case MsgPackType.NEGATIVE_FIXNUM_0x1E: + case MsgPackType.NEGATIVE_FIXNUM_0x1F: + return bytes.Advance(1).Take(0); + + case MsgPackType.UINT8: + case MsgPackType.INT8: + return bytes.Advance(1).Take(1); + + case MsgPackType.UINT16: + case MsgPackType.INT16: + return bytes.Advance(1).Take(2); + + case MsgPackType.UINT32: + case MsgPackType.INT32: + case MsgPackType.FLOAT: + return bytes.Advance(1).Take(4); + + case MsgPackType.UINT64: + case MsgPackType.INT64: + case MsgPackType.DOUBLE: + return bytes.Advance(1).Take(8); + + case MsgPackType.FIX_EXT_1: + return bytes.Advance(2).Take(1); + case MsgPackType.FIX_EXT_2: + return bytes.Advance(2).Take(2); + case MsgPackType.FIX_EXT_4: + return bytes.Advance(2).Take(4); + case MsgPackType.FIX_EXT_8: + return bytes.Advance(2).Take(8); + case MsgPackType.FIX_EXT_16: + return bytes.Advance(2).Take(16); + case MsgPackType.EXT8: + { + var count = bytes.Get(1); + return bytes.Advance(1 + 1 + 1).Take(count); + } + case MsgPackType.EXT16: + { + var count = EndianConverter.NetworkByteWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 2 + 1).Take(count); + } + case MsgPackType.EXT32: + { + var count = EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(bytes.Advance(1)); + return bytes.Advance(1 + 4 + 1).Take((int)count); + } + default: + throw new ArgumentException("unknown type: " + formatType); + } + } + + public SByte GetExtType() + { + var formatType = Format; + switch (formatType) + { + case MsgPackType.FIX_EXT_4: + return (SByte)Bytes.Get(1); + } + + throw new NotImplementedException(); + } + + /// + /// ArrayとMap以外のタイプの値を得る + /// + /// + public T GetValue() + { + var formatType = Format; + switch (formatType) + { + case MsgPackType.NIL: return GenericCast.Null(); + case MsgPackType.TRUE: return GenericCast.Const(true)(); + case MsgPackType.FALSE: return GenericCast.Const(false)(); + case MsgPackType.POSITIVE_FIXNUM: return GenericCast.Const(0)(); + case MsgPackType.POSITIVE_FIXNUM_0x01: return GenericCast.Const(1)(); + case MsgPackType.POSITIVE_FIXNUM_0x02: return GenericCast.Const(2)(); + case MsgPackType.POSITIVE_FIXNUM_0x03: return GenericCast.Const(3)(); + case MsgPackType.POSITIVE_FIXNUM_0x04: return GenericCast.Const(4)(); + case MsgPackType.POSITIVE_FIXNUM_0x05: return GenericCast.Const(5)(); + case MsgPackType.POSITIVE_FIXNUM_0x06: return GenericCast.Const(6)(); + case MsgPackType.POSITIVE_FIXNUM_0x07: return GenericCast.Const(7)(); + case MsgPackType.POSITIVE_FIXNUM_0x08: return GenericCast.Const(8)(); + case MsgPackType.POSITIVE_FIXNUM_0x09: return GenericCast.Const(9)(); + case MsgPackType.POSITIVE_FIXNUM_0x0A: return GenericCast.Const(10)(); + case MsgPackType.POSITIVE_FIXNUM_0x0B: return GenericCast.Const(11)(); + case MsgPackType.POSITIVE_FIXNUM_0x0C: return GenericCast.Const(12)(); + case MsgPackType.POSITIVE_FIXNUM_0x0D: return GenericCast.Const(13)(); + case MsgPackType.POSITIVE_FIXNUM_0x0E: return GenericCast.Const(14)(); + case MsgPackType.POSITIVE_FIXNUM_0x0F: return GenericCast.Const(15)(); + + case MsgPackType.POSITIVE_FIXNUM_0x10: return GenericCast.Const(16)(); + case MsgPackType.POSITIVE_FIXNUM_0x11: return GenericCast.Const(17)(); + case MsgPackType.POSITIVE_FIXNUM_0x12: return GenericCast.Const(18)(); + case MsgPackType.POSITIVE_FIXNUM_0x13: return GenericCast.Const(19)(); + case MsgPackType.POSITIVE_FIXNUM_0x14: return GenericCast.Const(20)(); + case MsgPackType.POSITIVE_FIXNUM_0x15: return GenericCast.Const(21)(); + case MsgPackType.POSITIVE_FIXNUM_0x16: return GenericCast.Const(22)(); + case MsgPackType.POSITIVE_FIXNUM_0x17: return GenericCast.Const(23)(); + case MsgPackType.POSITIVE_FIXNUM_0x18: return GenericCast.Const(24)(); + case MsgPackType.POSITIVE_FIXNUM_0x19: return GenericCast.Const(25)(); + case MsgPackType.POSITIVE_FIXNUM_0x1A: return GenericCast.Const(26)(); + case MsgPackType.POSITIVE_FIXNUM_0x1B: return GenericCast.Const(27)(); + case MsgPackType.POSITIVE_FIXNUM_0x1C: return GenericCast.Const(28)(); + case MsgPackType.POSITIVE_FIXNUM_0x1D: return GenericCast.Const(29)(); + case MsgPackType.POSITIVE_FIXNUM_0x1E: return GenericCast.Const(30)(); + case MsgPackType.POSITIVE_FIXNUM_0x1F: return GenericCast.Const(31)(); + + case MsgPackType.POSITIVE_FIXNUM_0x20: return GenericCast.Const(32)(); + case MsgPackType.POSITIVE_FIXNUM_0x21: return GenericCast.Const(33)(); + case MsgPackType.POSITIVE_FIXNUM_0x22: return GenericCast.Const(34)(); + case MsgPackType.POSITIVE_FIXNUM_0x23: return GenericCast.Const(35)(); + case MsgPackType.POSITIVE_FIXNUM_0x24: return GenericCast.Const(36)(); + case MsgPackType.POSITIVE_FIXNUM_0x25: return GenericCast.Const(37)(); + case MsgPackType.POSITIVE_FIXNUM_0x26: return GenericCast.Const(38)(); + case MsgPackType.POSITIVE_FIXNUM_0x27: return GenericCast.Const(39)(); + case MsgPackType.POSITIVE_FIXNUM_0x28: return GenericCast.Const(40)(); + case MsgPackType.POSITIVE_FIXNUM_0x29: return GenericCast.Const(41)(); + case MsgPackType.POSITIVE_FIXNUM_0x2A: return GenericCast.Const(42)(); + case MsgPackType.POSITIVE_FIXNUM_0x2B: return GenericCast.Const(43)(); + case MsgPackType.POSITIVE_FIXNUM_0x2C: return GenericCast.Const(44)(); + case MsgPackType.POSITIVE_FIXNUM_0x2D: return GenericCast.Const(45)(); + case MsgPackType.POSITIVE_FIXNUM_0x2E: return GenericCast.Const(46)(); + case MsgPackType.POSITIVE_FIXNUM_0x2F: return GenericCast.Const(47)(); + + case MsgPackType.POSITIVE_FIXNUM_0x30: return GenericCast.Const(48)(); + case MsgPackType.POSITIVE_FIXNUM_0x31: return GenericCast.Const(49)(); + case MsgPackType.POSITIVE_FIXNUM_0x32: return GenericCast.Const(50)(); + case MsgPackType.POSITIVE_FIXNUM_0x33: return GenericCast.Const(51)(); + case MsgPackType.POSITIVE_FIXNUM_0x34: return GenericCast.Const(52)(); + case MsgPackType.POSITIVE_FIXNUM_0x35: return GenericCast.Const(53)(); + case MsgPackType.POSITIVE_FIXNUM_0x36: return GenericCast.Const(54)(); + case MsgPackType.POSITIVE_FIXNUM_0x37: return GenericCast.Const(55)(); + case MsgPackType.POSITIVE_FIXNUM_0x38: return GenericCast.Const(56)(); + case MsgPackType.POSITIVE_FIXNUM_0x39: return GenericCast.Const(57)(); + case MsgPackType.POSITIVE_FIXNUM_0x3A: return GenericCast.Const(58)(); + case MsgPackType.POSITIVE_FIXNUM_0x3B: return GenericCast.Const(59)(); + case MsgPackType.POSITIVE_FIXNUM_0x3C: return GenericCast.Const(60)(); + case MsgPackType.POSITIVE_FIXNUM_0x3D: return GenericCast.Const(61)(); + case MsgPackType.POSITIVE_FIXNUM_0x3E: return GenericCast.Const(62)(); + case MsgPackType.POSITIVE_FIXNUM_0x3F: return GenericCast.Const(63)(); + + case MsgPackType.POSITIVE_FIXNUM_0x40: return GenericCast.Const(64)(); + case MsgPackType.POSITIVE_FIXNUM_0x41: return GenericCast.Const(65)(); + case MsgPackType.POSITIVE_FIXNUM_0x42: return GenericCast.Const(66)(); + case MsgPackType.POSITIVE_FIXNUM_0x43: return GenericCast.Const(67)(); + case MsgPackType.POSITIVE_FIXNUM_0x44: return GenericCast.Const(68)(); + case MsgPackType.POSITIVE_FIXNUM_0x45: return GenericCast.Const(69)(); + case MsgPackType.POSITIVE_FIXNUM_0x46: return GenericCast.Const(70)(); + case MsgPackType.POSITIVE_FIXNUM_0x47: return GenericCast.Const(71)(); + case MsgPackType.POSITIVE_FIXNUM_0x48: return GenericCast.Const(72)(); + case MsgPackType.POSITIVE_FIXNUM_0x49: return GenericCast.Const(73)(); + case MsgPackType.POSITIVE_FIXNUM_0x4A: return GenericCast.Const(74)(); + case MsgPackType.POSITIVE_FIXNUM_0x4B: return GenericCast.Const(75)(); + case MsgPackType.POSITIVE_FIXNUM_0x4C: return GenericCast.Const(76)(); + case MsgPackType.POSITIVE_FIXNUM_0x4D: return GenericCast.Const(77)(); + case MsgPackType.POSITIVE_FIXNUM_0x4E: return GenericCast.Const(78)(); + case MsgPackType.POSITIVE_FIXNUM_0x4F: return GenericCast.Const(79)(); + + case MsgPackType.POSITIVE_FIXNUM_0x50: return GenericCast.Const(80)(); + case MsgPackType.POSITIVE_FIXNUM_0x51: return GenericCast.Const(81)(); + case MsgPackType.POSITIVE_FIXNUM_0x52: return GenericCast.Const(82)(); + case MsgPackType.POSITIVE_FIXNUM_0x53: return GenericCast.Const(83)(); + case MsgPackType.POSITIVE_FIXNUM_0x54: return GenericCast.Const(84)(); + case MsgPackType.POSITIVE_FIXNUM_0x55: return GenericCast.Const(85)(); + case MsgPackType.POSITIVE_FIXNUM_0x56: return GenericCast.Const(86)(); + case MsgPackType.POSITIVE_FIXNUM_0x57: return GenericCast.Const(87)(); + case MsgPackType.POSITIVE_FIXNUM_0x58: return GenericCast.Const(88)(); + case MsgPackType.POSITIVE_FIXNUM_0x59: return GenericCast.Const(89)(); + case MsgPackType.POSITIVE_FIXNUM_0x5A: return GenericCast.Const(90)(); + case MsgPackType.POSITIVE_FIXNUM_0x5B: return GenericCast.Const(91)(); + case MsgPackType.POSITIVE_FIXNUM_0x5C: return GenericCast.Const(92)(); + case MsgPackType.POSITIVE_FIXNUM_0x5D: return GenericCast.Const(93)(); + case MsgPackType.POSITIVE_FIXNUM_0x5E: return GenericCast.Const(94)(); + case MsgPackType.POSITIVE_FIXNUM_0x5F: return GenericCast.Const(95)(); + + case MsgPackType.POSITIVE_FIXNUM_0x60: return GenericCast.Const(96)(); + case MsgPackType.POSITIVE_FIXNUM_0x61: return GenericCast.Const(97)(); + case MsgPackType.POSITIVE_FIXNUM_0x62: return GenericCast.Const(98)(); + case MsgPackType.POSITIVE_FIXNUM_0x63: return GenericCast.Const(99)(); + case MsgPackType.POSITIVE_FIXNUM_0x64: return GenericCast.Const(100)(); + case MsgPackType.POSITIVE_FIXNUM_0x65: return GenericCast.Const(101)(); + case MsgPackType.POSITIVE_FIXNUM_0x66: return GenericCast.Const(102)(); + case MsgPackType.POSITIVE_FIXNUM_0x67: return GenericCast.Const(103)(); + case MsgPackType.POSITIVE_FIXNUM_0x68: return GenericCast.Const(104)(); + case MsgPackType.POSITIVE_FIXNUM_0x69: return GenericCast.Const(105)(); + case MsgPackType.POSITIVE_FIXNUM_0x6A: return GenericCast.Const(106)(); + case MsgPackType.POSITIVE_FIXNUM_0x6B: return GenericCast.Const(107)(); + case MsgPackType.POSITIVE_FIXNUM_0x6C: return GenericCast.Const(108)(); + case MsgPackType.POSITIVE_FIXNUM_0x6D: return GenericCast.Const(109)(); + case MsgPackType.POSITIVE_FIXNUM_0x6E: return GenericCast.Const(110)(); + case MsgPackType.POSITIVE_FIXNUM_0x6F: return GenericCast.Const(111)(); + + case MsgPackType.POSITIVE_FIXNUM_0x70: return GenericCast.Const(112)(); + case MsgPackType.POSITIVE_FIXNUM_0x71: return GenericCast.Const(113)(); + case MsgPackType.POSITIVE_FIXNUM_0x72: return GenericCast.Const(114)(); + case MsgPackType.POSITIVE_FIXNUM_0x73: return GenericCast.Const(115)(); + case MsgPackType.POSITIVE_FIXNUM_0x74: return GenericCast.Const(116)(); + case MsgPackType.POSITIVE_FIXNUM_0x75: return GenericCast.Const(117)(); + case MsgPackType.POSITIVE_FIXNUM_0x76: return GenericCast.Const(118)(); + case MsgPackType.POSITIVE_FIXNUM_0x77: return GenericCast.Const(119)(); + case MsgPackType.POSITIVE_FIXNUM_0x78: return GenericCast.Const(120)(); + case MsgPackType.POSITIVE_FIXNUM_0x79: return GenericCast.Const(121)(); + case MsgPackType.POSITIVE_FIXNUM_0x7A: return GenericCast.Const(122)(); + case MsgPackType.POSITIVE_FIXNUM_0x7B: return GenericCast.Const(123)(); + case MsgPackType.POSITIVE_FIXNUM_0x7C: return GenericCast.Const(124)(); + case MsgPackType.POSITIVE_FIXNUM_0x7D: return GenericCast.Const(125)(); + case MsgPackType.POSITIVE_FIXNUM_0x7E: return GenericCast.Const(126)(); + case MsgPackType.POSITIVE_FIXNUM_0x7F: return GenericCast.Const(127)(); + + case MsgPackType.NEGATIVE_FIXNUM: return GenericCast.Const(-32)(); + case MsgPackType.NEGATIVE_FIXNUM_0x01: return GenericCast.Const(-1)(); + case MsgPackType.NEGATIVE_FIXNUM_0x02: return GenericCast.Const(-2)(); + case MsgPackType.NEGATIVE_FIXNUM_0x03: return GenericCast.Const(-3)(); + case MsgPackType.NEGATIVE_FIXNUM_0x04: return GenericCast.Const(-4)(); + case MsgPackType.NEGATIVE_FIXNUM_0x05: return GenericCast.Const(-5)(); + case MsgPackType.NEGATIVE_FIXNUM_0x06: return GenericCast.Const(-6)(); + case MsgPackType.NEGATIVE_FIXNUM_0x07: return GenericCast.Const(-7)(); + case MsgPackType.NEGATIVE_FIXNUM_0x08: return GenericCast.Const(-8)(); + case MsgPackType.NEGATIVE_FIXNUM_0x09: return GenericCast.Const(-9)(); + case MsgPackType.NEGATIVE_FIXNUM_0x0A: return GenericCast.Const(-10)(); + case MsgPackType.NEGATIVE_FIXNUM_0x0B: return GenericCast.Const(-11)(); + case MsgPackType.NEGATIVE_FIXNUM_0x0C: return GenericCast.Const(-12)(); + case MsgPackType.NEGATIVE_FIXNUM_0x0D: return GenericCast.Const(-13)(); + case MsgPackType.NEGATIVE_FIXNUM_0x0E: return GenericCast.Const(-14)(); + case MsgPackType.NEGATIVE_FIXNUM_0x0F: return GenericCast.Const(-15)(); + case MsgPackType.NEGATIVE_FIXNUM_0x10: return GenericCast.Const(-16)(); + case MsgPackType.NEGATIVE_FIXNUM_0x11: return GenericCast.Const(-17)(); + case MsgPackType.NEGATIVE_FIXNUM_0x12: return GenericCast.Const(-18)(); + case MsgPackType.NEGATIVE_FIXNUM_0x13: return GenericCast.Const(-19)(); + case MsgPackType.NEGATIVE_FIXNUM_0x14: return GenericCast.Const(-20)(); + case MsgPackType.NEGATIVE_FIXNUM_0x15: return GenericCast.Const(-21)(); + case MsgPackType.NEGATIVE_FIXNUM_0x16: return GenericCast.Const(-22)(); + case MsgPackType.NEGATIVE_FIXNUM_0x17: return GenericCast.Const(-23)(); + case MsgPackType.NEGATIVE_FIXNUM_0x18: return GenericCast.Const(-24)(); + case MsgPackType.NEGATIVE_FIXNUM_0x19: return GenericCast.Const(-25)(); + case MsgPackType.NEGATIVE_FIXNUM_0x1A: return GenericCast.Const(-26)(); + case MsgPackType.NEGATIVE_FIXNUM_0x1B: return GenericCast.Const(-27)(); + case MsgPackType.NEGATIVE_FIXNUM_0x1C: return GenericCast.Const(-28)(); + case MsgPackType.NEGATIVE_FIXNUM_0x1D: return GenericCast.Const(-29)(); + case MsgPackType.NEGATIVE_FIXNUM_0x1E: return GenericCast.Const(-30)(); + case MsgPackType.NEGATIVE_FIXNUM_0x1F: return GenericCast.Const(-31)(); + + case MsgPackType.INT8: return GenericCast.Cast((SByte)GetBody().Get(0)); + case MsgPackType.INT16: return GenericCast.Cast(EndianConverter.NetworkByteWordToSignedNativeByteOrder(GetBody())); + case MsgPackType.INT32: return GenericCast.Cast(EndianConverter.NetworkByteDWordToSignedNativeByteOrder(GetBody())); + case MsgPackType.INT64: return GenericCast.Cast(EndianConverter.NetworkByteQWordToSignedNativeByteOrder(GetBody())); + case MsgPackType.UINT8: return GenericCast.Cast(GetBody().Get(0)); + case MsgPackType.UINT16: return GenericCast.Cast(EndianConverter.NetworkByteWordToUnsignedNativeByteOrder(GetBody())); + case MsgPackType.UINT32: return GenericCast.Cast(EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(GetBody())); + case MsgPackType.UINT64: return GenericCast.Cast(EndianConverter.NetworkByteQWordToUnsignedNativeByteOrder(GetBody())); + case MsgPackType.FLOAT: return GenericCast.Cast(EndianConverter.NetworkByteDWordToFloatNativeByteOrder(GetBody())); + case MsgPackType.DOUBLE: return GenericCast.Cast(EndianConverter.NetworkByteQWordToFloatNativeByteOrder(GetBody())); + + case MsgPackType.FIX_STR: return GenericCast.Const("")(); + case MsgPackType.FIX_STR_0x01: + case MsgPackType.FIX_STR_0x02: + case MsgPackType.FIX_STR_0x03: + case MsgPackType.FIX_STR_0x04: + case MsgPackType.FIX_STR_0x05: + case MsgPackType.FIX_STR_0x06: + case MsgPackType.FIX_STR_0x07: + case MsgPackType.FIX_STR_0x08: + case MsgPackType.FIX_STR_0x09: + case MsgPackType.FIX_STR_0x0A: + case MsgPackType.FIX_STR_0x0B: + case MsgPackType.FIX_STR_0x0C: + case MsgPackType.FIX_STR_0x0D: + case MsgPackType.FIX_STR_0x0E: + case MsgPackType.FIX_STR_0x0F: + case MsgPackType.FIX_STR_0x10: + case MsgPackType.FIX_STR_0x11: + case MsgPackType.FIX_STR_0x12: + case MsgPackType.FIX_STR_0x13: + case MsgPackType.FIX_STR_0x14: + case MsgPackType.FIX_STR_0x15: + case MsgPackType.FIX_STR_0x16: + case MsgPackType.FIX_STR_0x17: + case MsgPackType.FIX_STR_0x18: + case MsgPackType.FIX_STR_0x19: + case MsgPackType.FIX_STR_0x1A: + case MsgPackType.FIX_STR_0x1B: + case MsgPackType.FIX_STR_0x1C: + case MsgPackType.FIX_STR_0x1D: + case MsgPackType.FIX_STR_0x1E: + case MsgPackType.FIX_STR_0x1F: + case MsgPackType.STR8: + case MsgPackType.STR16: + case MsgPackType.STR32: + { + var body = GetBody(); + var str = Encoding.UTF8.GetString(body.Array, body.Offset, body.Count); + return GenericCast.Cast(str); + } + + case MsgPackType.BIN8: + case MsgPackType.BIN16: + case MsgPackType.BIN32: + { + var body = GetBody(); + return GenericCast, T>.Cast(body); + } + + case MsgPackType.FIX_EXT_4: + { + if (GetExtType() == -1) + { + var unixtime = EndianConverter.NetworkByteDWordToUnsignedNativeByteOrder(GetBody()); + var dt = new DateTimeOffset(unixtime * DateTimeOffsetExtensions.TicksPerSecond + DateTimeOffsetExtensions.EpocTime.Ticks, TimeSpan.Zero); + return GenericCast.Cast(dt); + } + break; + } + } + + throw new ArgumentException("GetValue to array or map: " + formatType); + } + + public bool GetBoolean() + { + switch (Format) + { + case MsgPackType.TRUE: return true; + case MsgPackType.FALSE: return false; + default: throw new MsgPackTypeException("Not boolean"); + } + } + + public ArraySegment GetBytes() + { + if (!Format.IsBinary()) + { + throw new MsgPackTypeException("Not bin"); + } + return GetBody(); + } + + public string GetString() + { + if (!Format.IsString()) + { + throw new MsgPackTypeException("Not str"); + } + var bytes = GetBody(); + return Encoding.UTF8.GetString(bytes.Array, bytes.Offset, bytes.Count); + } + + public Utf8String GetUtf8String() + { + if (!Format.IsString()) + { + throw new MsgPackTypeException("Not str"); + } + var bytes = GetBody(); + return new Utf8String(bytes); + } + + public SByte GetSByte() + { + return GetValue(); + } + + public Int16 GetInt16() + { + return GetValue(); + } + + public Int32 GetInt32() + { + return GetValue(); + } + + public Int64 GetInt64() + { + return GetValue(); + } + + public Byte GetByte() + { + return GetValue(); + } + + public UInt16 GetUInt16() + { + return GetValue(); + } + + public UInt32 GetUInt32() + { + return GetValue(); + } + + public UInt64 GetUInt64() + { + return GetValue(); + } + + public float GetSingle() + { + return GetValue(); + } + + public double GetDouble() + { + return GetValue(); + } + + public void SetValue(Utf8String jsonPointer, T value) + { + throw new NotImplementedException(); + } + + public void RemoveValue(Utf8String jsonPointer) + { + throw new NotImplementedException(); + } + + public void AddKey(Utf8String key) + { + throw new NotImplementedException(); + } + + public void AddValue(ArraySegment bytes, ValueNodeType valueType) + { + throw new NotImplementedException(); + } + } +} diff --git a/Scripts/MsgPack/MsgPackValue.cs.meta b/Scripts/MsgPack/MsgPackValue.cs.meta new file mode 100644 index 000000000..e67e534a4 --- /dev/null +++ b/Scripts/MsgPack/MsgPackValue.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e201eb676758d5d419ae0629fda171ac +timeCreated: 1540904080 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Rpc.meta b/Scripts/Rpc.meta new file mode 100644 index 000000000..b31ccf87a --- /dev/null +++ b/Scripts/Rpc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e9f4765570f7add459493027e7057429 +folderAsset: yes +timeCreated: 1543734557 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Rpc/IRpc.cs b/Scripts/Rpc/IRpc.cs new file mode 100644 index 000000000..a1906e01c --- /dev/null +++ b/Scripts/Rpc/IRpc.cs @@ -0,0 +1,84 @@ +namespace UniJSON +{ + public interface IRpc + { + void Request(Utf8String method); + void Request(Utf8String method, A0 a0); + void Request(Utf8String method, A0 a0, A1 a1); + void Request(Utf8String method, A0 a0, A1 a1, A2 a2); + void Request(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3); + void Request(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4); + void Request(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5); + void ResponseSuccess(int id); + void ResponseSuccess(int id, T result); + void ResponseError(int id, System.Exception error); + void Notify(Utf8String method); + void Notify(Utf8String method, A0 a0); + void Notify(Utf8String method, A0 a0, A1 a1); + void Notify(Utf8String method, A0 a0, A1 a1, A2 a2); + void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3); + void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4); + void Notify(Utf8String method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5); + } + + public static class RpcExtensions + { + public static void Request(this IRpc rpc, string method) + { + rpc.Request(Utf8String.From(method)); + } + public static void Request(this IRpc rpc, string method, A0 a0) + { + rpc.Request(Utf8String.From(method), a0); + } + public static void Request(this IRpc rpc, string method, A0 a0, A1 a1) + { + rpc.Request(Utf8String.From(method), a0, a1); + } + public static void Request(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2) + { + rpc.Request(Utf8String.From(method), a0, a1, a2); + } + public static void Request(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2, A3 a3) + { + rpc.Request(Utf8String.From(method), a0, a1, a2, a3); + } + public static void Request(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) + { + rpc.Request(Utf8String.From(method), a0, a1, a2, a3, a4); + } + public static void Request(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + rpc.Request(Utf8String.From(method), a0, a1, a2, a3, a4, a5); + } + + public static void Notify(this IRpc rpc, string method) + { + rpc.Notify(Utf8String.From(method)); + } + public static void Notify(this IRpc rpc, string method, A0 a0) + { + rpc.Notify(Utf8String.From(method), a0); + } + public static void Notify(this IRpc rpc, string method, A0 a0, A1 a1) + { + rpc.Notify(Utf8String.From(method), a0, a1); + } + public static void Notify(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2) + { + rpc.Notify(Utf8String.From(method), a0, a1, a2); + } + public static void Notify(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2, A3 a3) + { + rpc.Notify(Utf8String.From(method), a0, a1, a2, a3); + } + public static void Notify(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) + { + rpc.Notify(Utf8String.From(method), a0, a1, a2, a3, a4); + } + public static void Notify(this IRpc rpc, string method, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + rpc.Notify(Utf8String.From(method), a0, a1, a2, a3, a4, a5); + } + } +} diff --git a/Scripts/Rpc/IRpc.cs.meta b/Scripts/Rpc/IRpc.cs.meta new file mode 100644 index 000000000..dd1d74b33 --- /dev/null +++ b/Scripts/Rpc/IRpc.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 565cc7f9a76689a45b352370db24f90f +timeCreated: 1543734576 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Rpc/RpcDispatcher.cs b/Scripts/Rpc/RpcDispatcher.cs new file mode 100644 index 000000000..40b3aa80b --- /dev/null +++ b/Scripts/Rpc/RpcDispatcher.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; + + +namespace UniJSON +{ + public class RpcDispatcher + where T : IListTreeItem, IValue + { + delegate void Callback(int id, ListTreeNode args, IRpc f); + Dictionary m_map = new Dictionary(); + + #region Action + public void Register(string method, Action action) + { + m_map.Add(method, (id, args, f) => + { + var it = args.ArrayItems().GetEnumerator(); + + var a0 = default(A0); + it.MoveNext(); + it.Current.Deserialize(ref a0); + + try + { + action(a0); + f.ResponseSuccess(id); + } + catch(Exception ex) + { + f.ResponseError(id, ex); + } + }); + } + + public void Register(string method, Action action) + { + throw new NotImplementedException(); + } + #endregion + + #region Func + public void Register(string method, Func action) + { + m_map.Add(method, (id, args, f) => + { + var it = args.ArrayItems().GetEnumerator(); + + var a0 = default(A0); + it.MoveNext(); + it.Current.Deserialize(ref a0); + + var a1 = default(A1); + it.MoveNext(); + it.Current.Deserialize(ref a1); + + try + { + var r = action(a0, a1); + f.ResponseSuccess(id, r); + } + catch(Exception ex) + { + f.ResponseError(id, ex); + } + }); + } + #endregion + + public void Call(IRpc f, int id, string method, ListTreeNode args) + { + Callback callback; + if (!m_map.TryGetValue(method, out callback)) + { + throw new KeyNotFoundException(); + } + callback(id, args, f); + } + } +} diff --git a/Scripts/Rpc/RpcDispatcher.cs.meta b/Scripts/Rpc/RpcDispatcher.cs.meta new file mode 100644 index 000000000..912d71720 --- /dev/null +++ b/Scripts/Rpc/RpcDispatcher.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 648f9a3ef9c1a6f41b11198b1f499d5c +timeCreated: 1543549119 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Toml.meta b/Scripts/Toml.meta new file mode 100644 index 000000000..a58d5b658 --- /dev/null +++ b/Scripts/Toml.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ebc8d8c2347b31d4a8023a91b95f618e +folderAsset: yes +timeCreated: 1545735556 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Toml/TomlParser.cs b/Scripts/Toml/TomlParser.cs new file mode 100644 index 000000000..c48ed5682 --- /dev/null +++ b/Scripts/Toml/TomlParser.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; + + +namespace UniJSON +{ + public static class TomlParser + { + static TomlValue ParseLHS(Utf8String segment, int parentIndex) + { + var it = segment.GetIterator(); + while (it.MoveNext()) + { + if (it.Current == '"') + { + throw new NotImplementedException(); + } + else if (it.Current == '.') + { + throw new NotImplementedException(); + } + else if (it.Current == ' ' || it.Current == '\t' || it.Current == '=') + { + return new TomlValue(segment.Subbytes(0, it.BytePosition), + TomlValueType.BareKey, parentIndex); + } + } + + throw new NotImplementedException(); + } + + static TomlValue ParseRHS(Utf8String segment, int parentIndex) + { + switch ((char)segment[0]) + { + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (segment.IsInt) + { + return new TomlValue(segment.SplitInteger(), TomlValueType.Integer, parentIndex); + } + else + { + return new TomlValue(segment, TomlValueType.Float, parentIndex); + } + + case '"': + { + int pos; + if (segment.TrySearchAscii((Byte)'"', 1, out pos)) + { + return new TomlValue(segment.Subbytes(0, pos + 1), TomlValueType.BasicString, parentIndex); + } + else + { + throw new ParserException("no close string: " + segment); + } + } + + case '[': + { + throw new NotImplementedException(); + } + } + + throw new NotImplementedException(); + } + + public static ListTreeNode Parse(Utf8String segment) + { + var values = new List() + { + new TomlValue(segment, TomlValueType.Table, -1), + }; + var current = 0; + + while (!segment.IsEmpty) + { + segment = segment.TrimStart(); + if (segment.IsEmpty) + { + break; + } + + if (segment[0] == '#') + { + // comment line + // skip to line end + segment = segment.Subbytes(segment.GetLine().ByteLength); + continue; + } + + if (segment.ByteLength>=4 && segment[0]=='[' && segment[1]=='[') + { + // [[array_name]] + throw new NotImplementedException(); + } + else if (segment.ByteLength>=2 && segment[0]=='[') + { + // [table_name] + int table_end; + if (!segment.TrySearchByte(x => x == ']', out table_end)) + { + throw new ParserException("] not found"); + } + var table_name = segment.Subbytes(1, table_end-1).Trim(); + if (table_name.IsEmpty) + { + throw new ParserException("empty table name"); + } + + // top level key + values.Add(new TomlValue(table_name, TomlValueType.Table, 0)); + current = values.Count - 1; + + // skip to line end + segment = segment.Subbytes(segment.GetLine().ByteLength); + } + else + { + // key = value + { + var key = ParseLHS(segment, current); + switch(key.TomlValueType) + { + case TomlValueType.BareKey: + case TomlValueType.QuotedKey: + { + values.Add(key); + + // skip key + segment = segment.Subbytes(key.Bytes.Count); + } + break; + + case TomlValueType.DottedKey: + throw new NotImplementedException(); + } + } + + { + // search and skip = + int eq; + if (!segment.TrySearchByte(x => x == '=', out eq)) + { + throw new ParserException("= not found"); + } + segment = segment.Subbytes(eq + 1); + + // skip white space + segment = segment.TrimStart(); + } + + { + var value = ParseRHS(segment, current); + values.Add(value); + + // skip value + segment = segment.Subbytes(value.Bytes.Count); + + // skip to line end + segment = segment.Subbytes(segment.GetLine().ByteLength); + } + } + } + + return new ListTreeNode(values); + } + + public static ListTreeNode Parse(String Toml) + { + return Parse(Utf8String.From(Toml)); + } + } +} diff --git a/Scripts/Toml/TomlParser.cs.meta b/Scripts/Toml/TomlParser.cs.meta new file mode 100644 index 000000000..553353580 --- /dev/null +++ b/Scripts/Toml/TomlParser.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3fcee2cba67aa504a9385323813c07df +timeCreated: 1545735557 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Toml/TomlValue.cs b/Scripts/Toml/TomlValue.cs new file mode 100644 index 000000000..7f02197d4 --- /dev/null +++ b/Scripts/Toml/TomlValue.cs @@ -0,0 +1,154 @@ +using System; + + +namespace UniJSON +{ + public enum TomlValueType + { + BareKey, // key + QuotedKey, // "key" + DottedKey, // key.nested + BasicString, // "str" + MultilineBasicString, // """str""" + LiteralString, // 'str' + MultilineLiteralString, // '''str''' + Integer, + Float, + Boolean, + OffsetDatetime, + Array, // [1, 2, 3] + Table, // [table_name] + } + + public struct TomlValue : IListTreeItem, IValue + { + public override string ToString() + { + return m_segment.ToString(); + } + + public int ParentIndex { get; private set; } + + public TomlValueType TomlValueType + { + get; + private set; + } + + public ValueNodeType ValueType + { + get + { + switch (TomlValueType) + { + case TomlValueType.Integer: return ValueNodeType.Integer; + case TomlValueType.Float: return ValueNodeType.Number; + case TomlValueType.Boolean: return ValueNodeType.Boolean; + + case TomlValueType.BareKey: return ValueNodeType.String; + case TomlValueType.QuotedKey: return ValueNodeType.String; + case TomlValueType.DottedKey: return ValueNodeType.String; + + case TomlValueType.BasicString: return ValueNodeType.String; + case TomlValueType.MultilineBasicString: return ValueNodeType.String; + case TomlValueType.LiteralString: return ValueNodeType.String; + case TomlValueType.MultilineLiteralString: return ValueNodeType.String; + + case TomlValueType.Table: return ValueNodeType.Object; + case TomlValueType.Array: return ValueNodeType.Array; + } + throw new NotImplementedException(); + } + } + + Utf8String m_segment; + public ArraySegment Bytes { get { return m_segment.Bytes; } } + + public TomlValue(Utf8String segment, TomlValueType valueType, int parentIndex) : this() + { + ParentIndex = parentIndex; + TomlValueType = valueType; + m_segment = segment; + } + + public bool GetBoolean() + { + throw new NotImplementedException(); + } + + public byte GetByte() + { + throw new NotImplementedException(); + } + + public double GetDouble() + { + throw new NotImplementedException(); + } + + public short GetInt16() + { + throw new NotImplementedException(); + } + + public int GetInt32() + { + return m_segment.ToInt32(); + } + + public long GetInt64() + { + throw new NotImplementedException(); + } + + public sbyte GetSByte() + { + throw new NotImplementedException(); + } + + public float GetSingle() + { + throw new NotImplementedException(); + } + + public string GetString() + { + throw new NotImplementedException(); + } + + public ushort GetUInt16() + { + throw new NotImplementedException(); + } + + public uint GetUInt32() + { + throw new NotImplementedException(); + } + + public ulong GetUInt64() + { + throw new NotImplementedException(); + } + + public Utf8String GetUtf8String() + { + return m_segment; + } + + public U GetValue() + { + throw new NotImplementedException(); + } + + public TomlValue Key(Utf8String key, int parentIndex) + { + throw new NotImplementedException(); + } + + public TomlValue New(ArraySegment bytes, ValueNodeType valueType, int parentIndex) + { + throw new NotImplementedException(); + } + } +} diff --git a/Scripts/Toml/TomlValue.cs.meta b/Scripts/Toml/TomlValue.cs.meta new file mode 100644 index 000000000..5443be452 --- /dev/null +++ b/Scripts/Toml/TomlValue.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e62dc750f570d764ab8c88742ceaa383 +timeCreated: 1545735558 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String.meta b/Scripts/Utf8String.meta new file mode 100644 index 000000000..e62a8f04e --- /dev/null +++ b/Scripts/Utf8String.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0e40e6ba8a3b47845ab0c82501dbb7d1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String/IUtf8String.cs b/Scripts/Utf8String/IUtf8String.cs new file mode 100644 index 000000000..e46cbc037 --- /dev/null +++ b/Scripts/Utf8String/IUtf8String.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Linq; + + +namespace UniJSON +{ + public interface IUtf8String: IEnumerable + { + int ByteLength { get; } + } + + /// + /// Immutable short utf8 string + /// + [StructLayout(LayoutKind.Explicit)] + public struct Utf8String4 : IEquatable, IUtf8String + { + [FieldOffset(0)] + uint _value; + + [FieldOffset(0)] + byte _byte0; + + [FieldOffset(1)] + byte _byte1; + + [FieldOffset(2)] + byte _byte2; + + [FieldOffset(3)] + byte _byte3; + + public int ByteLength + { + get + { + if (_byte0 == 0) return 0; + if (_byte1 == 0) return 1; + if (_byte2 == 0) return 2; + if (_byte3 == 0) return 3; + return 4; + } + } + + static Utf8String4 Create(uint value) + { + return new Utf8String4 + { + _value = value + }; + } + + public static Utf8String4 Create(IEnumerable bytes) + { + var u = new Utf8String4(); + var it = bytes.GetEnumerator(); + + if (!it.MoveNext()) return u; + u._byte0 = it.Current; + + if (!it.MoveNext()) return u; + u._byte1 = it.Current; + + if (!it.MoveNext()) return u; + u._byte2 = it.Current; + + if (!it.MoveNext()) return u; + u._byte3 = it.Current; + + if (!it.MoveNext()) + { + throw new ArgumentOutOfRangeException(); + } + + return u; + } + + public static Utf8String4 Create(string src) + { + return Create(Utf8String.Encoding.GetBytes(src)); + } + + public bool Equals(Utf8String4 other) + { + return _value == other._value; + } + + public override bool Equals(object obj) + { + if (obj == null) return false; + + if (obj is Utf8String4) + { + return Equals((Utf8String4)obj); + } + + { + var s = obj as string; + if (s != null) + { + return ToString() == s; + } + } + + return false; + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + public override string ToString() + { + return Utf8String.Encoding.GetString(this.ToArray()); + } + + public IEnumerator GetEnumerator() + { + if (_byte0 == 0) yield break; + yield return _byte0; + if (_byte1 == 0) yield break; + yield return _byte1; + if (_byte2 == 0) yield break; + yield return _byte2; + if (_byte3 == 0) yield break; + yield return _byte3; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/Scripts/Utf8String/IUtf8String.cs.meta b/Scripts/Utf8String/IUtf8String.cs.meta new file mode 100644 index 000000000..9e2b5f497 --- /dev/null +++ b/Scripts/Utf8String/IUtf8String.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d41f7c86ebb46934c8511b31de827279 +timeCreated: 1543422872 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String/Utf8Iterator.cs b/Scripts/Utf8String/Utf8Iterator.cs new file mode 100644 index 000000000..e712159a4 --- /dev/null +++ b/Scripts/Utf8String/Utf8Iterator.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections; +using System.Collections.Generic; + + +namespace UniJSON +{ + public struct Utf8Iterator : IEnumerator + { + Byte[] m_bytes; + int m_offset; + int m_start; + int m_position; + int m_end; + + public Utf8Iterator(ArraySegment range, int start = 0) + { + m_bytes = range.Array; + m_offset = range.Offset; + m_start = m_offset + start; + m_position = -1; + m_end = range.Offset + range.Count; + } + + public int BytePosition + { + get { return m_position - m_offset; } + } + + public int CurrentByteLength + { + get + { + var firstByte = Current; + if (firstByte <= 0x7F) + { + return 1; + } + else if (firstByte <= 0xDF) + { + return 2; + } + else if (firstByte <= 0xEF) + { + return 3; + } + else if (firstByte <= 0xF7) + { + return 4; + } + else + { + throw new Exception("invalid utf8"); + } + } + } + + public byte Current + { + get { return m_bytes[m_position]; } + } + + object IEnumerator.Current + { + get { return Current; } + } + + public byte Second + { + get { return m_bytes[m_position + 1]; } + } + + public byte Third + { + get { return m_bytes[m_position + 2]; } + } + + public byte Fourth + { + get { return m_bytes[m_position + 3]; } + } + + public const uint Mask1 = 0x01; + public const uint Mask2 = 0x03; + public const uint Mask3 = 0x07; + public const uint Mask4 = 0x0F; + public const uint Mask5 = 0x1F; + public const uint Mask6 = 0x3F; + public const uint Mask7 = 0x7F; + public const uint Mask11 = 0x07FF; + + public const uint Head1 = 0x80; + public const uint Head2 = 0xC0; + public const uint Head3 = 0xE0; + public const uint Head4 = 0xF0; + + public static int ByteLengthFromChar(char c) + { + if (c <= Mask7) + { + return 1; + } + else if (c <= Mask11) + { + return 2; + } + else + { + return 3; + } + } + + public uint Unicode + { + get + { + var l = CurrentByteLength; + if (l == 1) + { + // 7bit + return Current; + } + else if (l == 2) + { + // 11bit + return (Mask5 & Current) << 6 | (Mask6 & Second); + } + else if (l == 3) + { + // 16bit + return (Mask4 & Current) << 12 | (Mask6 & Second) << 6 | (Mask6 & Third); + } + else if (l == 4) + { + // 21bit + return (Mask3 & Current) << 18 | (Mask6 & Second) << 12 | (Mask6 & Third) << 6 | (Mask6 & Fourth); + } + else + { + throw new Exception("invalid utf8"); + } + } + } + + public char Char + { + get + { + var l = CurrentByteLength; + if (l == 1) + { + // 7bit + return (char)Current; + } + else if (l == 2) + { + // 11bit + return (char)((Mask5 & Current) << 6 | (Mask6 & Second)); + } + else if (l == 3) + { + // 16bit + return (char)((Mask4 & Current) << 12 | (Mask6 & Second) << 6 | (Mask6 & Third)); + } + else if (l == 4) + { + // 21bit + throw new NotImplementedException(); + } + else + { + throw new Exception("invalid utf8"); + } + } + } + + public void Dispose() + { + } + + public bool MoveNext() + { + if (m_position == -1) + { + m_position = m_start; + } + else + { + m_position += CurrentByteLength; + } + return m_position < m_end; + } + + public void Reset() + { + m_position = -1; + } + } +} diff --git a/Scripts/Utf8String/Utf8Iterator.cs.meta b/Scripts/Utf8String/Utf8Iterator.cs.meta new file mode 100644 index 000000000..65f901d60 --- /dev/null +++ b/Scripts/Utf8String/Utf8Iterator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a5c7531d2d3a77a4ba81e8ee43426726 +timeCreated: 1544057442 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String/Utf8String.cs b/Scripts/Utf8String/Utf8String.cs new file mode 100644 index 000000000..c3d6a7fec --- /dev/null +++ b/Scripts/Utf8String/Utf8String.cs @@ -0,0 +1,444 @@ +using System; +using System.Linq; + + +namespace UniJSON +{ + public struct Utf8String : IComparable + { + public static readonly System.Text.Encoding Encoding = new System.Text.UTF8Encoding(false); + + public readonly ArraySegment Bytes; + public int ByteLength + { + get { return Bytes.Count; } + } + + public Utf8Iterator GetIterator() + { + return new Utf8Iterator(Bytes); + } + + public int CompareTo(Utf8String other) + { + int i = 0; + for (; i < ByteLength && i < other.ByteLength; ++i) + { + if (this[i] < other[i]) + { + return 1; + } + else if (this[i] > other[i]) + { + return -1; + } + } + if (i < ByteLength) + { + return -1; + } + else if (i < other.ByteLength) + { + return 1; + } + else + { + return 0; + } + } + + public Byte this[int i] + { + get { return Bytes.Array[Bytes.Offset + i]; } + } + + public Utf8String(ArraySegment bytes) + { + Bytes = bytes; + } + + public Utf8String(Byte[] bytes, int offset, int count) : this(new ArraySegment(bytes, offset, count)) + { + } + + public Utf8String(Byte[] bytes) : this(bytes, 0, bytes.Length) + { + } + + public static Utf8String From(string src) + { + return new Utf8String(Encoding.GetBytes(src)); + } + + public static Utf8String From(string src, Byte[] bytes) + { + var required = src.Sum(c => Utf8Iterator.ByteLengthFromChar(c)); + if (required > bytes.Length) + { + throw new OverflowException(); + } + int pos = 0; + foreach (var c in src) + { + if (c <= Utf8Iterator.Mask7) + { + // 1bit + bytes[pos++] = (byte)c; + } + else if (c <= Utf8Iterator.Mask11) + { + // 2bit + bytes[pos++] = (byte)(Utf8Iterator.Head2 | Utf8Iterator.Mask5 & (c >> 6)); + bytes[pos++] = (byte)(Utf8Iterator.Head1 | Utf8Iterator.Mask6 & (c)); + } + else + { + // 3bit + bytes[pos++] = (byte)(Utf8Iterator.Head3 | Utf8Iterator.Mask4 & (c >> 12)); + bytes[pos++] = (byte)(Utf8Iterator.Head1 | Utf8Iterator.Mask6 & (c >> 6)); + bytes[pos++] = (byte)(Utf8Iterator.Head1 | Utf8Iterator.Mask6 & (c)); + } + } + return new Utf8String(new ArraySegment(bytes, 0, pos)); + } + + // -2147483648 ~ 2147483647 + public static Utf8String From(int src) + { + if (src >= 0) + { + if (src < 10) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src), + }); + } + else if (src < 100) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 1000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 10000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 100000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/10000), + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 1000000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/100000), + (byte)(0x30 + src/10000), + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 10000000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/1000000), + (byte)(0x30 + src/100000), + (byte)(0x30 + src/10000), + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 100000000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/10000000), + (byte)(0x30 + src/1000000), + (byte)(0x30 + src/100000), + (byte)(0x30 + src/10000), + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else if (src < 1000000000) + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/100000000), + (byte)(0x30 + src/10000000), + (byte)(0x30 + src/1000000), + (byte)(0x30 + src/100000), + (byte)(0x30 + src/10000), + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + else + { + return new Utf8String(new byte[] { + (byte)(0x30 + src/1000000000), + (byte)(0x30 + src/100000000), + (byte)(0x30 + src/10000000), + (byte)(0x30 + src/1000000), + (byte)(0x30 + src/100000), + (byte)(0x30 + src/10000), + (byte)(0x30 + src/1000), + (byte)(0x30 + src/100), + (byte)(0x30 + src/10), + (byte)(0x30 + src%10), + }); + } + } + else + { + throw new NotImplementedException(); + } + } + + public Utf8String Concat(Utf8String rhs) + { + var bytes = new Byte[ByteLength + rhs.ByteLength]; + Buffer.BlockCopy(Bytes.Array, Bytes.Offset, bytes, 0, ByteLength); + Buffer.BlockCopy(rhs.Bytes.Array, rhs.Bytes.Offset, bytes, ByteLength, rhs.ByteLength); + return new Utf8String(bytes); + } + + public override string ToString() + { + if (ByteLength == 0) return ""; + return Encoding.GetString(Bytes.Array, Bytes.Offset, Bytes.Count); + } + + public string ToAscii() + { + if (ByteLength == 0) return ""; + return System.Text.Encoding.ASCII.GetString(Bytes.Array, Bytes.Offset, Bytes.Count); + } + + public bool IsEmpty + { + get + { + return ByteLength == 0; + } + } + + public bool StartsWith(Utf8String rhs) + { + if (rhs.ByteLength > ByteLength) + { + return false; + } + + for (int i = 0; i < rhs.ByteLength; ++i) + { + if (this[i] != rhs[i]) + { + return false; + } + } + + return true; + } + + public bool EndsWith(Utf8String rhs) + { + if (rhs.ByteLength > ByteLength) + { + return false; + } + + for (int i = 1; i <= rhs.ByteLength; ++i) + { + if (this[ByteLength - i] != rhs[rhs.ByteLength - i]) + { + return false; + } + } + + return true; + } + + public int IndexOf(Byte code) + { + return IndexOf(0, code); + } + + public int IndexOf(int offset, Byte code) + { + var pos = offset + Bytes.Offset; + for (int i = 0; i < Bytes.Count; ++i, ++pos) + { + if (Bytes.Array[pos] == code) + { + return pos - Bytes.Offset; + } + } + return -1; + } + + public Utf8String Subbytes(int offset) + { + return Subbytes(offset, ByteLength - offset); + } + + public Utf8String Subbytes(int offset, int count) + { + return new Utf8String(Bytes.Array, Bytes.Offset + offset, count); + } + + static bool IsSpace(Byte b) + { + switch (b) + { + case 0x20: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x09: + return true; + } + + return false; + } + + public Utf8String TrimStart() + { + var i = 0; + for (; i < ByteLength; ++i) + { + if (!IsSpace(this[i])) + { + break; + } + } + return Subbytes(i); + } + + public Utf8String TrimEnd() + { + var i = ByteLength-1; + for (; i >= 0; --i) + { + if (!IsSpace(this[i])) + { + break; + } + } + return Subbytes(0, i+1); + } + + public Utf8String Trim() + { + return TrimStart().TrimEnd(); + } + + public override bool Equals(Object obj) + { + return obj is Utf8String && Equals((Utf8String)obj); + } + + public static bool operator ==(Utf8String x, Utf8String y) + { + return x.Equals(y); + } + + public static bool operator !=(Utf8String x, Utf8String y) + { + return !(x == y); + } + + public bool Equals(Utf8String other) + { + if (ByteLength != other.ByteLength) + { + return false; + } + + for (int i = 0; i < ByteLength; ++i) + { + if (this[i] != other[i]) + { + return false; + } + } + + return true; + } + + public override int GetHashCode() + { + return ByteLength.GetHashCode(); + } + + public static Utf8String operator +(Utf8String l, Utf8String r) + { + return new Utf8String(l.Bytes.Concat(r.Bytes)); + } + + public bool IsInt + { + get + { + //bool isInt = false; + for (int i = 0; i < ByteLength; ++i) + { + var c = this[i]; + if (c == '0' + || c == '1' + || c == '2' + || c == '3' + || c == '4' + || c == '5' + || c == '6' + || c == '7' + || c == '8' + || c == '9' + ) + { + // ok + //isInt = true; + } + else if (i == 0 && c == '-') + { + // ok + } + else if (c == '.' || c == 'e') + { + return false; + } + else + { + break; + } + } + return true; + } + } + } +} diff --git a/Scripts/Utf8String/Utf8String.cs.meta b/Scripts/Utf8String/Utf8String.cs.meta new file mode 100644 index 000000000..fa34c195a --- /dev/null +++ b/Scripts/Utf8String/Utf8String.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93adff1e1b4725f498a92faccf7e240d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String/Utf8StringBuilder.cs b/Scripts/Utf8String/Utf8StringBuilder.cs new file mode 100644 index 000000000..e638aabdc --- /dev/null +++ b/Scripts/Utf8String/Utf8StringBuilder.cs @@ -0,0 +1,33 @@ +using System.Text; + +namespace UniJSON +{ + public class Utf8StringBuilder + { + ByteBuffer m_buffer = new ByteBuffer(); + + public void Ascii(char c) + { + m_buffer.Push((byte)c); + } + + static Encoding s_utf8 = new UTF8Encoding(false); + + public void Quote(string text) + { + Ascii('"'); + m_buffer.Push(s_utf8.GetBytes(text)); + Ascii('"'); + } + + public void Add(Utf8String str) + { + m_buffer.Push(str.Bytes); + } + + public Utf8String ToUtf8String() + { + return new Utf8String(m_buffer.Bytes); + } + } +} diff --git a/Scripts/Utf8String/Utf8StringBuilder.cs.meta b/Scripts/Utf8String/Utf8StringBuilder.cs.meta new file mode 100644 index 000000000..d3d1cfd86 --- /dev/null +++ b/Scripts/Utf8String/Utf8StringBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba2dbf26152e2704d986754eb12f5af4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String/Utf8StringExtensions.cs b/Scripts/Utf8String/Utf8StringExtensions.cs new file mode 100644 index 000000000..db2682c49 --- /dev/null +++ b/Scripts/Utf8String/Utf8StringExtensions.cs @@ -0,0 +1,341 @@ +using System; +using System.Collections.Generic; +using System.IO; + + +namespace UniJSON +{ + public static class Utf8StringExtensions + { + public static void WriteTo(this Utf8String src, Stream dst) + { + dst.Write(src.Bytes.Array, src.Bytes.Offset, src.Bytes.Count); + } + + public static Utf8Iterator GetFirst(this Utf8String src) + { + var it = src.GetIterator(); + it.MoveNext(); + return it; + } + + public static bool TrySearchByte(this Utf8String src, Func pred, out int pos) + { + pos = 0; + for (; pos < src.ByteLength; ++pos) + { + if (pred(src[pos])) + { + return true; + } + } + return false; + } + + public static bool TrySearchAscii(this Utf8String src, Byte target, int start, out int pos) + { + var p = new Utf8Iterator(src.Bytes, start); + while (p.MoveNext()) + { + var b = p.Current; + if (b <= 0x7F) + { + // ascii + if (b == target/*'\"'*/) + { + // closed + pos = p.BytePosition; + return true; + } + else if (b == '\\') + { + // escaped + switch ((char)p.Second) + { + case '"': // fall through + case '\\': // fall through + case '/': // fall through + case 'b': // fall through + case 'f': // fall through + case 'n': // fall through + case 'r': // fall through + case 't': // fall through + // skip next + p.MoveNext(); + break; + + case 'u': // unicode + // skip next 4 + p.MoveNext(); + p.MoveNext(); + p.MoveNext(); + p.MoveNext(); + break; + + default: + // unkonw escape + throw new ParserException("unknown escape: " + p.Second); + } + } + } + } + + pos = -1; + return false; + } + + public static IEnumerable Split(this Utf8String src, byte delemeter) + { + var start = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + if (p.Current == delemeter) + { + if (p.BytePosition - start == 0) + { + yield return default(Utf8String); + } + else + { + yield return src.Subbytes(start, p.BytePosition - start); + } + start = p.BytePosition + 1; + } + } + + if (start < p.BytePosition) + { + yield return src.Subbytes(start, p.BytePosition - start); + } + } + + #region atoi + public static SByte ToSByte(this Utf8String src) + { + SByte value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (SByte)(value * 10); break; + case 0x31: value = (SByte)(value * 10 + 1); break; + case 0x32: value = (SByte)(value * 10 + 2); break; + case 0x33: value = (SByte)(value * 10 + 3); break; + case 0x34: value = (SByte)(value * 10 + 4); break; + case 0x35: value = (SByte)(value * 10 + 5); break; + case 0x36: value = (SByte)(value * 10 + 6); break; + case 0x37: value = (SByte)(value * 10 + 7); break; + case 0x38: value = (SByte)(value * 10 + 8); break; + case 0x39: value = (SByte)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + public static Int16 ToInt16(this Utf8String src) + { + Int16 value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (Int16)(value * 10); break; + case 0x31: value = (Int16)(value * 10 + 1); break; + case 0x32: value = (Int16)(value * 10 + 2); break; + case 0x33: value = (Int16)(value * 10 + 3); break; + case 0x34: value = (Int16)(value * 10 + 4); break; + case 0x35: value = (Int16)(value * 10 + 5); break; + case 0x36: value = (Int16)(value * 10 + 6); break; + case 0x37: value = (Int16)(value * 10 + 7); break; + case 0x38: value = (Int16)(value * 10 + 8); break; + case 0x39: value = (Int16)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + public static Int32 ToInt32(this Utf8String src) + { + Int32 value = 0; + Int32 sign = 1; + var p = new Utf8Iterator(src.Bytes); + bool isFirst = true; + while (p.MoveNext()) + { + var b = p.Current; + + if (isFirst) + { + isFirst = false; + if (b == '-') + { + sign = -1; + continue; + } + } + + switch (b) + { + case 0x30: value = value * 10; break; + case 0x31: value = value * 10 + 1; break; + case 0x32: value = value * 10 + 2; break; + case 0x33: value = value * 10 + 3; break; + case 0x34: value = value * 10 + 4; break; + case 0x35: value = value * 10 + 5; break; + case 0x36: value = value * 10 + 6; break; + case 0x37: value = value * 10 + 7; break; + case 0x38: value = value * 10 + 8; break; + case 0x39: value = value * 10 + 9; break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value * sign; + } + public static Int64 ToInt64(this Utf8String src) + { + Int64 value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (Int64)(value * 10); break; + case 0x31: value = (Int64)(value * 10 + 1); break; + case 0x32: value = (Int64)(value * 10 + 2); break; + case 0x33: value = (Int64)(value * 10 + 3); break; + case 0x34: value = (Int64)(value * 10 + 4); break; + case 0x35: value = (Int64)(value * 10 + 5); break; + case 0x36: value = (Int64)(value * 10 + 6); break; + case 0x37: value = (Int64)(value * 10 + 7); break; + case 0x38: value = (Int64)(value * 10 + 8); break; + case 0x39: value = (Int64)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + public static Byte ToByte(this Utf8String src) + { + Byte value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (Byte)(value * 10); break; + case 0x31: value = (Byte)(value * 10 + 1); break; + case 0x32: value = (Byte)(value * 10 + 2); break; + case 0x33: value = (Byte)(value * 10 + 3); break; + case 0x34: value = (Byte)(value * 10 + 4); break; + case 0x35: value = (Byte)(value * 10 + 5); break; + case 0x36: value = (Byte)(value * 10 + 6); break; + case 0x37: value = (Byte)(value * 10 + 7); break; + case 0x38: value = (Byte)(value * 10 + 8); break; + case 0x39: value = (Byte)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + public static UInt16 ToUInt16(this Utf8String src) + { + UInt16 value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (UInt16)(value * 10); break; + case 0x31: value = (UInt16)(value * 10 + 1); break; + case 0x32: value = (UInt16)(value * 10 + 2); break; + case 0x33: value = (UInt16)(value * 10 + 3); break; + case 0x34: value = (UInt16)(value * 10 + 4); break; + case 0x35: value = (UInt16)(value * 10 + 5); break; + case 0x36: value = (UInt16)(value * 10 + 6); break; + case 0x37: value = (UInt16)(value * 10 + 7); break; + case 0x38: value = (UInt16)(value * 10 + 8); break; + case 0x39: value = (UInt16)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + public static UInt32 ToUInt32(this Utf8String src) + { + UInt32 value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (UInt32)(value * 10); break; + case 0x31: value = (UInt32)(value * 10 + 1); break; + case 0x32: value = (UInt32)(value * 10 + 2); break; + case 0x33: value = (UInt32)(value * 10 + 3); break; + case 0x34: value = (UInt32)(value * 10 + 4); break; + case 0x35: value = (UInt32)(value * 10 + 5); break; + case 0x36: value = (UInt32)(value * 10 + 6); break; + case 0x37: value = (UInt32)(value * 10 + 7); break; + case 0x38: value = (UInt32)(value * 10 + 8); break; + case 0x39: value = (UInt32)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + public static UInt64 ToUInt64(this Utf8String src) + { + UInt64 value = 0; + var p = new Utf8Iterator(src.Bytes); + while (p.MoveNext()) + { + var b = p.Current; + switch (b) + { + case 0x30: value = (UInt64)(value * 10); break; + case 0x31: value = (UInt64)(value * 10 + 1); break; + case 0x32: value = (UInt64)(value * 10 + 2); break; + case 0x33: value = (UInt64)(value * 10 + 3); break; + case 0x34: value = (UInt64)(value * 10 + 4); break; + case 0x35: value = (UInt64)(value * 10 + 5); break; + case 0x36: value = (UInt64)(value * 10 + 6); break; + case 0x37: value = (UInt64)(value * 10 + 7); break; + case 0x38: value = (UInt64)(value * 10 + 8); break; + case 0x39: value = (UInt64)(value * 10 + 9); break; + default: throw new ArgumentOutOfRangeException(); + } + } + return value; + } + #endregion + + public static float ToSingle(this Utf8String src) + { + return Single.Parse(src.ToAscii(), System.Globalization.CultureInfo.InvariantCulture); + } + public static double ToDouble(this Utf8String src) + { + return Double.Parse(src.ToAscii(), System.Globalization.CultureInfo.InvariantCulture); + } + + public static Utf8String GetLine(this Utf8String src) + { + int pos; + if (!src.TrySearchAscii((byte)'\n', 0, out pos)) + { + return src; + } + + return src.Subbytes(0, pos + 1); + } + } +} diff --git a/Scripts/Utf8String/Utf8StringExtensions.cs.meta b/Scripts/Utf8String/Utf8StringExtensions.cs.meta new file mode 100644 index 000000000..edb9bdbd7 --- /dev/null +++ b/Scripts/Utf8String/Utf8StringExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f613907c8a91aa049809fe1f754776de +timeCreated: 1544060764 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Utf8String/Utf8StringSplitterExtensions.cs b/Scripts/Utf8String/Utf8StringSplitterExtensions.cs new file mode 100644 index 000000000..ed37f4897 --- /dev/null +++ b/Scripts/Utf8String/Utf8StringSplitterExtensions.cs @@ -0,0 +1,44 @@ +using System; + + +namespace UniJSON +{ + public static class Utf8StringSplitterExtensions + { + /// + /// Split integer from start + /// + /// "123 " => "123" + /// " 123" => FormatException + /// + /// must start +-0123456789 + /// + /// + /// + /// + public static Utf8String SplitInteger(this Utf8String src) + { + var i = 0; + if(src[0]=='+' || src[0] == '-') + { + ++i; + } + + var j = i; + for(; j'9') + { + break; + } + } + + if (i == j) + { + throw new FormatException(); + } + + return src.Subbytes(0, j); + } + } +} diff --git a/Scripts/Utf8String/Utf8StringSplitterExtensions.cs.meta b/Scripts/Utf8String/Utf8StringSplitterExtensions.cs.meta new file mode 100644 index 000000000..080f9ba26 --- /dev/null +++ b/Scripts/Utf8String/Utf8StringSplitterExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1627ff7e9bb16a8459021fda0223909c +timeCreated: 1545735556 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: