OSDN Git Service

JSONパーザーをDynaJsonに切り替える
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Util / JsonParser.cs
diff --git a/KancolleSniffer/Util/JsonParser.cs b/KancolleSniffer/Util/JsonParser.cs
deleted file mode 100644 (file)
index 2177f67..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-using System;\r
-using System.Collections;\r
-using System.Collections.Generic;\r
-using System.Collections.Specialized;\r
-using System.Dynamic;\r
-using System.Linq;\r
-using System.Reflection;\r
-using System.Text;\r
-using System.Text.RegularExpressions;\r
-\r
-namespace KancolleSniffer.Util\r
-{\r
-    public class JsonParser\r
-    {\r
-        private readonly string _source;\r
-        private int _position;\r
-\r
-        public static JsonObject Parse(string json)\r
-        {\r
-            return new JsonParser(json).Parse();\r
-        }\r
-\r
-        private JsonParser(string json)\r
-        {\r
-            _source = json;\r
-        }\r
-\r
-        private JsonObject Parse()\r
-        {\r
-            var ch = NextChar();\r
-            if ('0' <= ch && ch <= '9' || ch == '-')\r
-                return ParseNumber();\r
-            switch (ch)\r
-            {\r
-                case 'n':\r
-                    if (IsMatch("null"))\r
-                        return null;\r
-                    goto invalid;\r
-                case 't':\r
-                    if (IsMatch("true"))\r
-                        return new JsonObject(true);\r
-                    goto invalid;\r
-                case 'f':\r
-                    if (IsMatch("false"))\r
-                        return new JsonObject(false);\r
-                    goto invalid;\r
-                case '"':\r
-                    return ParseString();\r
-                case '[':\r
-                    return ParseArray();\r
-                case '{':\r
-                    return ParseObject();\r
-            }\r
-            invalid:\r
-            throw new JsonParserException($"'{ch}'不正な文字です。 at {_position}");\r
-        }\r
-\r
-        private bool IsMatch(string s)\r
-        {\r
-            foreach (char ch in s)\r
-            {\r
-                var src = LookAhead();\r
-                if (ch != src)\r
-                    return false;\r
-                Consume();\r
-            }\r
-            return true;\r
-        }\r
-\r
-        private JsonObject ParseNumber()\r
-        {\r
-            return new JsonObject(GetNumber());\r
-        }\r
-\r
-        private double GetNumber()\r
-        {\r
-            var result = 0d;\r
-            var ch = LookAhead();\r
-            var sign = 1d;\r
-            if (ch == '-')\r
-            {\r
-                sign = -1;\r
-                Consume();\r
-                ch = LookAhead();\r
-            }\r
-            while ('0' <= ch && ch <= '9')\r
-            {\r
-                result = (result * 10.0) + (ch - '0');\r
-                Consume();\r
-                ch = LookAhead();\r
-            }\r
-            if (ch != '.')\r
-                return sign * result;\r
-            var exp = 0.1;\r
-            Consume();\r
-            ch = LookAhead();\r
-            while ('0' <= ch && ch <= '9')\r
-            {\r
-                result += (ch - '0') * exp;\r
-                exp *= 0.1;\r
-                Consume();\r
-                ch = LookAhead();\r
-            }\r
-            return sign * result;\r
-        }\r
-\r
-        private JsonObject ParseString()\r
-        {\r
-            return new JsonObject(GetString());\r
-        }\r
-\r
-        private string GetString()\r
-        {\r
-            Consume();\r
-            var len = 0;\r
-            while (true)\r
-            {\r
-                var ch = LookAhead();\r
-                if (ch == '\\')\r
-                {\r
-                    Consume();\r
-                    Consume();\r
-                    len += 2;\r
-                    continue;\r
-                }\r
-                if (ch == '"')\r
-                {\r
-                    Consume();\r
-                    break;\r
-                }\r
-                len++;\r
-                Consume();\r
-            }\r
-            return UnEscape(_source.Substring(_position - len - 1, len));\r
-        }\r
-\r
-        private static readonly Regex EscapeRegex =\r
-            new Regex(@"\\[^u]|\\u(?:[0-9A-Fa-f]{4})", RegexOptions.Compiled);\r
-\r
-        private string UnEscape(string s)\r
-        {\r
-            return EscapeRegex.Replace(s, m =>\r
-            {\r
-                switch (m.Value[1])\r
-                {\r
-                    case '/':\r
-                        return '/'.ToString();\r
-                    case '"':\r
-                    case '\\':\r
-                    case 'b':\r
-                    case 'f':\r
-                    case 'n':\r
-                    case 'r':\r
-                    case 't':\r
-                    case 'u':\r
-                        return Regex.Unescape(m.Value).ToString();\r
-                    default:\r
-                        throw new JsonParserException("不正なエスケープシーケンスです。 at {");\r
-                }\r
-            });\r
-        }\r
-\r
-        private JsonObject ParseArray()\r
-        {\r
-            Consume();\r
-            var ary = new List<JsonObject>();\r
-            while (true)\r
-            {\r
-                var ch = NextChar();\r
-                if (ch == ']')\r
-                {\r
-                    Consume();\r
-                    return new JsonObject(ary);\r
-                }\r
-                ary.Add(Parse());\r
-                ch = NextChar();\r
-                if (ch != ',' && ch != ']')\r
-                    throw new JsonParserException($"','か']'が必要です。 at {_position}");\r
-                if (ch == ']')\r
-                {\r
-                    Consume();\r
-                    return new JsonObject(ary);\r
-                }\r
-                Consume();\r
-            }\r
-        }\r
-\r
-        private JsonObject ParseObject()\r
-        {\r
-            Consume();\r
-            var dict = new OrderedDictionary();\r
-            while (true)\r
-            {\r
-                var ch = NextChar();\r
-                if (ch == '}')\r
-                {\r
-                    Consume();\r
-                    return new JsonObject(dict);\r
-                }\r
-                if (ch != '"')\r
-                    throw new JsonParserException($"文字列が必要です。 at {_position}");\r
-                var key = GetString();\r
-                ch = NextChar();\r
-                if (ch != ':')\r
-                    throw new JsonParserException($"':'が必要です。 at {_position}");\r
-                Consume();\r
-                var value = Parse();\r
-                dict.Add(key, value);\r
-                ch = NextChar();\r
-                if (ch != ',' && ch != '}')\r
-                    throw new JsonParserException($"','か'}}'が必要です。 at {_position}");\r
-                if (ch == '}')\r
-                {\r
-                    Consume();\r
-                    return new JsonObject(dict);\r
-                }\r
-                Consume();\r
-            }\r
-        }\r
-\r
-        private char LookAhead()\r
-        {\r
-            if (_source.Length == _position)\r
-                return '\0';\r
-            return _source[_position];\r
-        }\r
-\r
-        private void Consume()\r
-        {\r
-            if (_source.Length == _position)\r
-                throw new JsonParserException($"入力が途切れています。 at {_position}");\r
-            _position++;\r
-        }\r
-\r
-        private char NextChar()\r
-        {\r
-            while (true)\r
-            {\r
-                var ch = LookAhead();\r
-                if (!(ch == '\r' || ch == '\n' || ch == '\t' || ch == ' '))\r
-                    return ch;\r
-                Consume();\r
-            }\r
-        }\r
-    }\r
-\r
-    public class JsonObject : DynamicObject\r
-    {\r
-        private readonly JsonType _type;\r
-        private readonly bool _bool;\r
-        private readonly double _number;\r
-        private readonly string _string;\r
-        private readonly List<JsonObject> _array;\r
-        private readonly OrderedDictionary _dict;\r
-\r
-        public bool IsArray => _type == JsonType.Array;\r
-        public bool IsObject => _type == JsonType.Object;\r
-        // ReSharper disable once UnusedMember.Global\r
-        public bool IsDefined(string attr) => IsObject && _dict.Contains(attr);\r
-\r
-        public JsonObject(bool b)\r
-        {\r
-            _type = JsonType.Bool;\r
-            _bool = b;\r
-        }\r
-\r
-        public JsonObject(double n)\r
-        {\r
-            _type = JsonType.Number;\r
-            _number = n;\r
-        }\r
-\r
-        public JsonObject(string s)\r
-        {\r
-            _type = JsonType.String;\r
-            _string = s;\r
-        }\r
-\r
-        public JsonObject(List<JsonObject> ary)\r
-        {\r
-            _type = JsonType.Array;\r
-            _array = ary;\r
-        }\r
-\r
-        public JsonObject(OrderedDictionary dict)\r
-        {\r
-            _type = JsonType.Object;\r
-            _dict = dict;\r
-        }\r
-\r
-        public override bool TryGetMember(GetMemberBinder binder, out object result)\r
-        {\r
-            result = null;\r
-            if (_type != JsonType.Object)\r
-                return false;\r
-            if (!_dict.Contains(binder.Name))\r
-                return false;\r
-            result = ((JsonObject)_dict[binder.Name])?.Value;\r
-            return true;\r
-        }\r
-\r
-        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)\r
-        {\r
-            result = _type == JsonType.Object && _dict.Contains(binder.Name);\r
-            return true;\r
-        }\r
-\r
-        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)\r
-        {\r
-            switch (_type)\r
-            {\r
-                case JsonType.Array:\r
-                    result = _array[(int)indexes[0]]?.Value;\r
-                    return true;\r
-                case JsonType.Object:\r
-                    result = ((JsonObject)_dict[(string)indexes[0]])?.Value;\r
-                    return true;\r
-            }\r
-            result = null;\r
-            return false;\r
-        }\r
-\r
-        public override bool TryConvert(ConvertBinder binder, out object result)\r
-        {\r
-            if (binder.Type == typeof(IEnumerable))\r
-            {\r
-                switch (_type)\r
-                {\r
-                    case JsonType.Array:\r
-                        result = _array.Select(x => x.Value);\r
-                        return true;\r
-                    case JsonType.Object:\r
-                        result = _dict.Cast<DictionaryEntry>().Select(x => new KeyValuePair<string, dynamic>((string)x.Key, x.Value));\r
-                        return true;\r
-                    default:\r
-                        result = null;\r
-                        return false;\r
-                }\r
-            }\r
-            if (_type != JsonType.Array)\r
-                return ConvertPrivateType(binder.Type, out result);\r
-            if (binder.Type == typeof(int[]))\r
-            {\r
-                result = _array.Select(x => (int)x._number).ToArray();\r
-                return true;\r
-            }\r
-            if (binder.Type.IsArray)\r
-            {\r
-                return ConvertArray(binder.Type.GetElementType(), _array, out result);\r
-            }\r
-            result = null;\r
-            return false;\r
-        }\r
-\r
-        private bool ConvertPrivateType(Type type, out object result)\r
-        {\r
-            if (type == typeof(bool) && _type == JsonType.Bool)\r
-            {\r
-                result = _bool;\r
-                return true;\r
-            }\r
-            if (type == typeof(int) && _type == JsonType.Number)\r
-            {\r
-                result = (int)_number;\r
-                return true;\r
-            }\r
-            if (type == typeof(double) && _type == JsonType.Number)\r
-            {\r
-                result = _number;\r
-                return true;\r
-            }\r
-            if (type == typeof(string) && _type == JsonType.String)\r
-            {\r
-                result = _string;\r
-                return true;\r
-            }\r
-            if (type == typeof(object))\r
-            {\r
-                result = Value;\r
-                return true;\r
-            }\r
-            result = null;\r
-            return false;\r
-        }\r
-\r
-        private bool ConvertArray(Type type, List<JsonObject> values, out object result)\r
-        {\r
-            result = null;\r
-            var array = Array.CreateInstance(type, values.Count);\r
-            for (var i = 0; i < array.Length; i++)\r
-            {\r
-                if (type.IsArray)\r
-                {\r
-                    if (!values[i].IsArray || !ConvertArray(type.GetElementType(), values[i]._array, out var one))\r
-                        return false;\r
-                    array.SetValue((dynamic)one, i);\r
-                }\r
-                else\r
-                {\r
-                    if (!values[i].ConvertPrivateType(type, out var one))\r
-                        return false;\r
-                    array.SetValue((dynamic)one, i);\r
-                }\r
-            }\r
-            result = array;\r
-            return true;\r
-        }\r
-\r
-        public static JsonObject CreateJsonObject(object value)\r
-        {\r
-            switch (value)\r
-            {\r
-                case string s:\r
-                    return new JsonObject(s);\r
-                case int i:\r
-                    return new JsonObject(i);\r
-                case double d:\r
-                    return new JsonObject(d);\r
-                case JsonObject json:\r
-                    return json;\r
-                case IEnumerable ary:\r
-                    return new JsonObject(ary.Cast<object>().Select(CreateJsonObject).ToList());\r
-                case object obj:\r
-                    var dict = new OrderedDictionary();\r
-                    foreach (var prop in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))\r
-                        dict.Add(prop.Name, CreateJsonObject(prop.GetValue(obj)));\r
-                    return new JsonObject(dict);\r
-            }\r
-            return null;\r
-        }\r
-\r
-        public override bool TrySetMember(SetMemberBinder binder, object value)\r
-        {\r
-            if (_type != JsonType.Object)\r
-                return false;\r
-            _dict[binder.Name] = CreateJsonObject(value);\r
-            return true;\r
-        }\r
-\r
-        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)\r
-        {\r
-            if (_type == JsonType.Array)\r
-            {\r
-                _array[(int)indexes[0]] = CreateJsonObject(value);\r
-                return true;\r
-            }\r
-            if (_type == JsonType.Object)\r
-            {\r
-                _dict[(string)indexes[0]] = CreateJsonObject(value);\r
-                return true;\r
-            }\r
-            return false;\r
-        }\r
-\r
-        public override string ToString()\r
-        {\r
-            var sb = new StringBuilder();\r
-            ConvertToString(sb);\r
-            return sb.ToString();\r
-        }\r
-\r
-        private void ConvertToString(StringBuilder sb)\r
-        {\r
-            switch (_type)\r
-            {\r
-                case JsonType.Bool:\r
-                    sb.Append(_bool ? "true" : "false");\r
-                    break;\r
-                case JsonType.Number:\r
-                    sb.Append(_number.ToString("G"));\r
-                    break;\r
-                case JsonType.String:\r
-                    sb.Append("\"");\r
-                    sb.Append(HttpUtility.JavascriptStringEncode(_string));\r
-                    sb.Append("\"");\r
-                    break;\r
-                case JsonType.Array:\r
-                    sb.Append("[");\r
-                    var delimiter = "";\r
-                    foreach (var val in _array)\r
-                    {\r
-                        sb.Append(delimiter);\r
-                        if (val == null)\r
-                        {\r
-                            sb.Append("null");\r
-                        }\r
-                        else\r
-                        {\r
-                            val.ConvertToString(sb);\r
-                        }\r
-                        delimiter = ",";\r
-                    }\r
-                    sb.Append("]");\r
-                    break;\r
-                case JsonType.Object:\r
-                    sb.Append("{");\r
-                    delimiter = "";\r
-                    foreach (DictionaryEntry entry in _dict)\r
-                    {\r
-                        sb.Append(delimiter);\r
-                        sb.Append("\"");\r
-                        sb.Append(entry.Key);\r
-                        sb.Append("\":");\r
-                        if (entry.Value == null)\r
-                        {\r
-                            sb.Append("null");\r
-                        }\r
-                        else\r
-                        {\r
-                            ((JsonObject)entry.Value).ConvertToString(sb);\r
-                        }\r
-                        delimiter = ",";\r
-                    }\r
-                    sb.Append("}");\r
-                    break;\r
-            }\r
-        }\r
-\r
-        private object Value\r
-        {\r
-            get\r
-            {\r
-                switch (_type)\r
-                {\r
-                    case JsonType.Bool:\r
-                        return _bool;\r
-                    case JsonType.Number:\r
-                        return _number;\r
-                    case JsonType.String:\r
-                        return _string;\r
-                }\r
-                return this;\r
-            }\r
-        }\r
-\r
-        private enum JsonType\r
-        {\r
-            Bool,\r
-            Number,\r
-            String,\r
-            Array,\r
-            Object\r
-        }\r
-    }\r
-\r
-    public class JsonParserException : Exception\r
-    {\r
-        public JsonParserException(string message) : base(message)\r
-        {\r
-        }\r
-    }\r
-}
\ No newline at end of file