diff --git a/.idea/.idea.VAR.Json/.idea/.gitignore b/.idea/.idea.VAR.Json/.idea/.gitignore new file mode 100644 index 0000000..60335c0 --- /dev/null +++ b/.idea/.idea.VAR.Json/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/.idea.VAR.Json.iml +/modules.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.VAR.Json/.idea/encodings.xml b/.idea/.idea.VAR.Json/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.VAR.Json/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.VAR.Json/.idea/indexLayout.xml b/.idea/.idea.VAR.Json/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.VAR.Json/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.VAR.Json/.idea/vcs.xml b/.idea/.idea.VAR.Json/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.VAR.Json/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 6a6ef58..41c79b1 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2021 Valeriano Alfonso Rodriguez +Copyright (c) 2016-2022 Valeriano Alfonso Rodriguez Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 041fb6e..585983a 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ## Usage ### VAR.Json + Add the resulting assembly as reference in your projects, and this line on code: ```csharp @@ -10,18 +11,20 @@ using VAR.Json; ``` Parse any string with JSON content: + ```csharp object result = JsonParser.ParseText("{\"Test\": 1}"); ``` Serialize any object to JSON: + ```csharp string jsonText = JsonWriter.WriteObject(new List{1, 2, 3, 4}); ``` ### VAR.Json.JsonParser -This object can be invoked with a list of types used to cast the json objects. +This object can be invoked with a list of types used to cast the json objects. ```csharp @@ -37,13 +40,14 @@ jsonParser.KnownTypes.Add(typeof(Person)); Person jsonText = jsonParser.Parse("{ \"Name\": \"John", \"Surname\": \"Doe\", \"DateOfBirth\": \"1970-01-01\"}") as Person; ``` - ## Building + A Visual Studio solution is provided. Simply, click build on the IDE. The build generates a DLL and a Nuget package. ## Contributing + 1. Fork it! 2. Create your feature branch: `git checkout -b my-new-feature` 3. Commit your changes: `git commit -am 'Add some feature'` @@ -51,4 +55,5 @@ The build generates a DLL and a Nuget package. 5. Submit a pull request :D ## Credits + * Valeriano Alfonso Rodriguez. diff --git a/VAR.Json.Tests/JsonParser_Tests.cs b/VAR.Json.Tests/JsonParser_Tests.cs index 2676a9b..0b4d264 100644 --- a/VAR.Json.Tests/JsonParser_Tests.cs +++ b/VAR.Json.Tests/JsonParser_Tests.cs @@ -7,7 +7,7 @@ namespace VAR.Json.Tests { #region Parse - public class SwallowObject + private class SwallowObject { public string Text { get; set; } public int Number { get; set; } @@ -20,11 +20,11 @@ namespace VAR.Json.Tests parser.KnownTypes.Add(typeof(SwallowObject)); SwallowObject result = parser.Parse(@"{""Text"": ""AAAA"", ""Number"": 42}") as SwallowObject; Assert.False(parser.Tainted); - Assert.Equal("AAAA", result.Text); + Assert.Equal("AAAA", result?.Text); Assert.Equal(42, result.Number); } - public class DeeperObject_L1 + private class DeeperObject_L1 { public string Name { get; set; } public SwallowObject Object { get; set; } @@ -36,14 +36,16 @@ namespace VAR.Json.Tests JsonParser parser = new JsonParser(); parser.KnownTypes.Add(typeof(SwallowObject)); parser.KnownTypes.Add(typeof(DeeperObject_L1)); - DeeperObject_L1 result = parser.Parse(@"{""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}") as DeeperObject_L1; + DeeperObject_L1 result = + parser.Parse(@"{""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}") as + DeeperObject_L1; Assert.False(parser.Tainted); Assert.Equal("Thing", result.Name); Assert.Equal("AAAA", result.Object.Text); Assert.Equal(42, result.Object.Number); } - public class DeeperObject_L2 + private class DeeperObject_L2 { public int Count { get; set; } public DeeperObject_L1 Object { get; set; } @@ -56,7 +58,10 @@ namespace VAR.Json.Tests parser.KnownTypes.Add(typeof(SwallowObject)); parser.KnownTypes.Add(typeof(DeeperObject_L1)); parser.KnownTypes.Add(typeof(DeeperObject_L2)); - DeeperObject_L2 result = parser.Parse(@"{""Count"": 1, ""Object"": {""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}}") as DeeperObject_L2; + DeeperObject_L2 result = + parser.Parse( + @"{""Count"": 1, ""Object"": {""Name"": ""Thing"", ""Object"": {""Text"": ""AAAA"", ""Number"": 42}}}") + as DeeperObject_L2; Assert.False(parser.Tainted); Assert.Equal(1, result.Count); Assert.Equal("Thing", result.Object.Name); @@ -76,7 +81,7 @@ namespace VAR.Json.Tests Assert.Equal(42, result[0].Number); } - public class DeeperObjectArray_L1 + private class DeeperObjectArray_L1 { public int Count { get; set; } public List Array { get; set; } @@ -88,14 +93,16 @@ namespace VAR.Json.Tests JsonParser parser = new JsonParser(); parser.KnownTypes.Add(typeof(SwallowObject)); parser.KnownTypes.Add(typeof(DeeperObjectArray_L1)); - DeeperObjectArray_L1 result = parser.Parse(@"{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}") as DeeperObjectArray_L1; + DeeperObjectArray_L1 result = + parser.Parse(@"{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}") as + DeeperObjectArray_L1; Assert.False(parser.Tainted); Assert.Equal(1, result.Count); Assert.Equal("AAAA", result.Array[0].Text); Assert.Equal(42, result.Array[0].Number); } - public class DeeperObjectArray_L2 + private class DeeperObjectArray_L2 { public string Name { get; set; } public List Objects { get; set; } @@ -108,7 +115,10 @@ namespace VAR.Json.Tests parser.KnownTypes.Add(typeof(SwallowObject)); parser.KnownTypes.Add(typeof(DeeperObjectArray_L1)); parser.KnownTypes.Add(typeof(DeeperObjectArray_L2)); - DeeperObjectArray_L2 result = parser.Parse(@"{""Name"": ""Thing"", ""Objects"": [{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}]}") as DeeperObjectArray_L2; + DeeperObjectArray_L2 result = + parser.Parse( + @"{""Name"": ""Thing"", ""Objects"": [{""Count"": 1, ""Array"": [{""Text"": ""AAAA"", ""Number"": 42}]}]}") + as DeeperObjectArray_L2; Assert.False(parser.Tainted); Assert.Equal("Thing", result.Name); Assert.Equal(1, result.Objects[0].Count); @@ -124,7 +134,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail01() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"""A JSON payload should be an object or array, not a string."""); + parser.Parse(@"""A JSON payload should be an object or array, not a string."""); Assert.True(parser.Tainted); } @@ -132,7 +142,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail02() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Unclosed array"""); + parser.Parse(@"[""Unclosed array"""); Assert.True(parser.Tainted); } @@ -140,7 +150,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail03() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{unquoted_key: ""keys must be quoted""}"); + parser.Parse(@"{unquoted_key: ""keys must be quoted""}"); Assert.True(parser.Tainted); } @@ -148,7 +158,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail04() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""extra comma"",]"); + parser.Parse(@"[""extra comma"",]"); Assert.True(parser.Tainted); } @@ -156,7 +166,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail05() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""double extra comma"",,]"); + parser.Parse(@"[""double extra comma"",,]"); Assert.True(parser.Tainted); } @@ -164,7 +174,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail06() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[ , ""<-- missing value""]"); + parser.Parse(@"[ , ""<-- missing value""]"); Assert.True(parser.Tainted); } @@ -172,7 +182,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail07() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Comma after the close""],"); + parser.Parse(@"[""Comma after the close""],"); Assert.True(parser.Tainted); } @@ -180,7 +190,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail08() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Extra close""]]"); + parser.Parse(@"[""Extra close""]]"); Assert.True(parser.Tainted); } @@ -188,7 +198,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail09() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Extra comma"": true,}"); + parser.Parse(@"{""Extra comma"": true,}"); Assert.True(parser.Tainted); } @@ -196,7 +206,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail10() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Extra value after close"": true} ""misplaced quoted value"""); + parser.Parse(@"{""Extra value after close"": true} ""misplaced quoted value"""); Assert.True(parser.Tainted); } @@ -204,7 +214,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail11() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Illegal expression"": 1 + 2}"); + parser.Parse(@"{""Illegal expression"": 1 + 2}"); Assert.True(parser.Tainted); } @@ -212,7 +222,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail12() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Illegal invocation"": alert()}"); + parser.Parse(@"{""Illegal invocation"": alert()}"); Assert.True(parser.Tainted); } @@ -220,7 +230,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail13() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Numbers cannot have leading zeroes"": 013}"); + parser.Parse(@"{""Numbers cannot have leading zeroes"": 013}"); Assert.True(parser.Tainted); } @@ -228,7 +238,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail14() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Numbers cannot be hex"": 0x14}"); + parser.Parse(@"{""Numbers cannot be hex"": 0x14}"); Assert.True(parser.Tainted); } @@ -236,7 +246,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail15() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Illegal backslash escape: \x15""]"); + parser.Parse(@"[""Illegal backslash escape: \x15""]"); Assert.True(parser.Tainted); } @@ -244,7 +254,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail16() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[\naked]"); + parser.Parse(@"[\naked]"); Assert.True(parser.Tainted); } @@ -252,7 +262,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail17() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Illegal backslash escape: \017""]"); + parser.Parse(@"[""Illegal backslash escape: \017""]"); Assert.True(parser.Tainted); } @@ -260,7 +270,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail18() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[[[[[[[[[[[[[[[[[[[[""Too deep""]]]]]]]]]]]]]]]]]]]]"); + parser.Parse(@"[[[[[[[[[[[[[[[[[[[[""Too deep""]]]]]]]]]]]]]]]]]]]]"); Assert.True(parser.Tainted); } @@ -268,7 +278,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail19() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Missing colon"" null}"); + parser.Parse(@"{""Missing colon"" null}"); Assert.True(parser.Tainted); } @@ -276,7 +286,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail20() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Double colon"":: null}"); + parser.Parse(@"{""Double colon"":: null}"); Assert.True(parser.Tainted); } @@ -284,7 +294,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail21() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Comma instead of colon"", null}"); + parser.Parse(@"{""Comma instead of colon"", null}"); Assert.True(parser.Tainted); } @@ -292,7 +302,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail22() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Colon instead of comma"": false]"); + parser.Parse(@"[""Colon instead of comma"": false]"); Assert.True(parser.Tainted); } @@ -300,7 +310,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail23() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""Bad value"", truth]"); + parser.Parse(@"[""Bad value"", truth]"); Assert.True(parser.Tainted); } @@ -308,7 +318,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail24() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"['single quote']"); + parser.Parse(@"['single quote']"); Assert.True(parser.Tainted); } @@ -316,7 +326,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail25() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"["" tab character in string ""]"); + parser.Parse(@"["" tab character in string ""]"); Assert.True(parser.Tainted); } @@ -324,7 +334,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail26() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""tab\ character\ in\ string\ ""]"); + parser.Parse(@"[""tab\ character\ in\ string\ ""]"); Assert.True(parser.Tainted); } @@ -332,7 +342,7 @@ namespace VAR.Json.Tests public void Parse__Validity_Fail27() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""line + parser.Parse(@"[""line break""]"); Assert.True(parser.Tainted); } @@ -341,7 +351,7 @@ break""]"); public void Parse__Validity_Fail28() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""line\ + parser.Parse(@"[""line\ break""]"); Assert.True(parser.Tainted); } @@ -350,7 +360,7 @@ break""]"); public void Parse__Validity_Fail29() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[0e]"); + parser.Parse(@"[0e]"); Assert.True(parser.Tainted); } @@ -358,7 +368,7 @@ break""]"); public void Parse__Validity_Fail30() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[0e+]"); + parser.Parse(@"[0e+]"); Assert.True(parser.Tainted); } @@ -366,7 +376,7 @@ break""]"); public void Parse__Validity_Fail31() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[0e+-1]"); + parser.Parse(@"[0e+-1]"); Assert.True(parser.Tainted); } @@ -374,7 +384,7 @@ break""]"); public void Parse__Validity_Fail32() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{""Comma instead if closing brace"": true,"); + parser.Parse(@"{""Comma instead if closing brace"": true,"); Assert.True(parser.Tainted); } @@ -382,7 +392,7 @@ break""]"); public void Parse__Validity_Fail33() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[""mismatch""}"); + parser.Parse(@"[""mismatch""}"); Assert.True(parser.Tainted); } @@ -390,7 +400,7 @@ break""]"); public void Parse__Validity_Pass01() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[ + parser.Parse(@"[ ""JSON Test Pattern pass1"", {""object with 1 member"":[""array with 1 element""]}, {}, @@ -455,7 +465,7 @@ break""]"); public void Parse__Validity_Pass02() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"[[[[[[[[[[[[[[[[[[[""Not too deep""]]]]]]]]]]]]]]]]]]]"); + parser.Parse(@"[[[[[[[[[[[[[[[[[[[""Not too deep""]]]]]]]]]]]]]]]]]]]"); Assert.False(parser.Tainted); } @@ -463,7 +473,7 @@ break""]"); public void Parse__Validity_Pass03() { JsonParser parser = new JsonParser(); - object result = parser.Parse(@"{ + parser.Parse(@"{ ""JSON Test Pattern pass3"": { ""The outermost value"": ""must be an object or array."", ""In this test"": ""It is an object."" diff --git a/VAR.Json.Tests/VAR.Json.Tests.csproj b/VAR.Json.Tests/VAR.Json.Tests.csproj index ddab021..5f882ac 100644 --- a/VAR.Json.Tests/VAR.Json.Tests.csproj +++ b/VAR.Json.Tests/VAR.Json.Tests.csproj @@ -1,26 +1,26 @@ - - net5.0 + + net5.0 - false - + false + - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - + + + diff --git a/VAR.Json.sln.DotSettings b/VAR.Json.sln.DotSettings new file mode 100644 index 0000000..5de9805 --- /dev/null +++ b/VAR.Json.sln.DotSettings @@ -0,0 +1,55 @@ + + NotRequired + True + True + TOGETHER_SAME_LINE + True + True + False + True + True + True + OneStep + OneStep + True + UseVarWhenEvident + UseVarWhenEvident + AES + AM + AUX + CYC + DC + DES + EPM + GDI + ID + IP + RECT + RGB + SCART + SPDIF + SQL + SRCCOPY + TCP + URL + USB + VAR + WMIC + YRYBY + False + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb"><ExtraRule Prefix="T" Suffix="" Style="AaBb_AaBb" /></Policy> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb_AaBb" /> + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb_AaBb" /> + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + \ No newline at end of file diff --git a/VAR.Json/JsonParser.cs b/VAR.Json/JsonParser.cs index 51e5a87..d2801df 100644 --- a/VAR.Json/JsonParser.cs +++ b/VAR.Json/JsonParser.cs @@ -13,7 +13,7 @@ namespace VAR.Json private const int MaxRecursiveCount = 20; private ParserContext _ctx; - private bool _tainted = false; + private bool _tainted; private readonly List _knownTypes = new List(); @@ -21,38 +21,31 @@ namespace VAR.Json #region Properties - public bool Tainted - { - get { return _tainted; } - } + public bool Tainted => _tainted; - public List KnownTypes - { - get { return _knownTypes; } - } + public List KnownTypes => _knownTypes; #endregion Properties #region Private methods - private static readonly Dictionary _dictProperties = new Dictionary(); + private static readonly Dictionary _dictProperties = + new Dictionary(); private PropertyInfo[] Type_GetProperties(Type type) { - PropertyInfo[] typeProperties = null; - if (_dictProperties.ContainsKey(type)) { typeProperties = _dictProperties[type]; } - else + PropertyInfo[] typeProperties; + lock (_dictProperties) { - lock (_dictProperties) + if (_dictProperties.ContainsKey(type)) { typeProperties = _dictProperties[type]; } + else { - if (_dictProperties.ContainsKey(type)) { typeProperties = _dictProperties[type]; } - else - { - typeProperties = type.GetProperties(BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.Instance); - _dictProperties.Add(type, typeProperties); - } + typeProperties = type.GetProperties(BindingFlags.Public | BindingFlags.OptionalParamBinding | + BindingFlags.Instance); + _dictProperties.Add(type, typeProperties); } } + return typeProperties; } @@ -67,7 +60,8 @@ namespace VAR.Json count++; } } - return ((float)count / (float)typeProperties.Length); + + return count / (float)typeProperties.Length; } private object ConvertToType(Dictionary obj, Type type) @@ -86,9 +80,9 @@ namespace VAR.Json { valueDest = null; } - else if (effectiveType == typeof(Guid) && valueOrig is string) + else if (effectiveType == typeof(Guid) && valueOrig is string valGuid) { - valueDest = new Guid((string)valueOrig); + valueDest = new Guid(valGuid); } else { @@ -101,9 +95,11 @@ namespace VAR.Json continue; } } + prop.SetValue(newObj, valueDest, null); } } + return newObj; } @@ -120,6 +116,7 @@ namespace VAR.Json bestMatchFactor = matchFactor; } } + if (bestMatch != null) { try @@ -127,8 +124,12 @@ namespace VAR.Json object newObj = ConvertToType(obj, bestMatch); return newObj; } - catch (Exception) { } /* Nom Nom */ + catch (Exception) + { + // ignored + } } + return obj; } @@ -151,6 +152,7 @@ namespace VAR.Json } } } + return value; } @@ -162,6 +164,7 @@ namespace VAR.Json { c = _ctx.Next(); } + do { if (c == '\\') @@ -208,6 +211,7 @@ namespace VAR.Json // StrictRules: Mark as tainted on unknown escaped character _tainted = true; } + c = _ctx.Next(); } else if (c == '"') @@ -217,13 +221,14 @@ namespace VAR.Json } else { - // StrictRules: Mark as tainted on ilegal characters + // StrictRules: Mark as tainted on illegal characters if (c == '\t' || c == '\n') { _tainted = true; } scratch.Append(c); c = _ctx.Next(); } } while (!_ctx.AtEnd()); + return scratch.ToString(); } @@ -235,6 +240,7 @@ namespace VAR.Json { c = _ctx.Next(); } + do { if (c == '\\') @@ -281,6 +287,7 @@ namespace VAR.Json // StrictRules: Mark as tainted on unknown escaped character _tainted = true; } + c = _ctx.Next(); } else if (c == '\'') @@ -290,13 +297,14 @@ namespace VAR.Json } else { - // StrictRules: Mark as tainted on ilegal characters + // StrictRules: Mark as tainted on illegal characters if (c == '\t' || c == '\n') { _tainted = true; } scratch.Append(c); c = _ctx.Next(); } } while (!_ctx.AtEnd()); + return scratch.ToString(); } @@ -307,16 +315,19 @@ namespace VAR.Json { return ParseQuotedString(); } + if (c == '\'') { _tainted = true; return ParseSingleQuotedString(); } + if (mustBeQuoted) { _tainted = true; } + StringBuilder scratch = new StringBuilder(); while (!_ctx.AtEnd() - && (char.IsLetter(c) || char.IsDigit(c) || c == '_')) + && (char.IsLetter(c) || char.IsDigit(c) || c == '_')) { scratch.Append(c); c = _ctx.Next(); @@ -332,8 +343,7 @@ namespace VAR.Json bool isExp = false; int numberLenght = 0; int expLenght = 0; - char c; - c = _ctx.SkipWhite(); + char c = _ctx.SkipWhite(); // Sign if (c == '-') @@ -394,6 +404,7 @@ namespace VAR.Json scratch.Append(c); c = _ctx.Next(); } + while (char.IsDigit(c)) { scratch.Append(c); @@ -443,6 +454,7 @@ namespace VAR.Json { _ctx.Next(); } + bool? expectValue = null; do { @@ -451,6 +463,7 @@ namespace VAR.Json { // StrictRules: Mark as tainted when unexpected end of array if (expectValue == true) { _tainted = true; } + correct = true; _ctx.Next(); break; @@ -467,6 +480,7 @@ namespace VAR.Json { // StrictRules: Mark as tainted when unexpected value on array if (expectValue == false) { _tainted = true; } + object value = ParseValue(recursiveCount + 1); array.Add(value); expectValue = false; @@ -475,6 +489,7 @@ namespace VAR.Json { Type valueType = value?.GetType(); if (valueType == null) { hasNulls = true; } + if (arrayContentType == null || arrayContentType == valueType) { arrayContentType = valueType; @@ -486,21 +501,24 @@ namespace VAR.Json } } } while (!_ctx.AtEnd()); + if (correct == false) { _tainted = true; } + object result = array; bool isNullableType = arrayContentType?.IsClass == true; - if (hasSameType && arrayContentType != null && (isNullableType == true || (isNullableType == false && hasNulls == false))) + if (hasSameType && arrayContentType != null && (isNullableType || (hasNulls == false))) { var enumerableType = typeof(System.Linq.Enumerable); - var castMethod = enumerableType.GetMethod("Cast").MakeGenericMethod(arrayContentType); - var toListMethod = enumerableType.GetMethod("ToList").MakeGenericMethod(arrayContentType); + var castMethod = enumerableType.GetMethod("Cast")?.MakeGenericMethod(arrayContentType); + var toListMethod = enumerableType.GetMethod("ToList")?.MakeGenericMethod(arrayContentType); IEnumerable itemsToCast = array; - var castedItems = castMethod.Invoke(null, new[] { itemsToCast }); - result = toListMethod.Invoke(null, new[] { castedItems }); + var castedItems = castMethod?.Invoke(null, new object[] { itemsToCast }); + result = toListMethod?.Invoke(null, new[] { castedItems }); } + return result; } @@ -516,8 +534,8 @@ namespace VAR.Json { _ctx.Next(); } + string attributeName = null; - object attributeValue; bool? expectedKey = null; bool? expectedValue = null; do @@ -528,7 +546,7 @@ namespace VAR.Json _ctx.Next(); if (expectedValue == true) { - attributeValue = ParseValue(recursiveCount + 1); + object attributeValue = ParseValue(recursiveCount + 1); obj.Add(attributeName, attributeValue); expectedKey = null; expectedValue = false; @@ -548,6 +566,7 @@ namespace VAR.Json { _tainted = true; } + correct = true; _ctx.Next(); break; @@ -569,15 +588,17 @@ namespace VAR.Json } } } while (!_ctx.AtEnd()); + if (correct == false) { _tainted = true; } + object result = TryConvertToTypes(obj); return result; } - private object ParseValue(int recusiveCount = 1) + private object ParseValue(int recursiveCount = 1) { char c = _ctx.SkipWhite(); object token; @@ -594,11 +615,11 @@ namespace VAR.Json break; case '{': - token = ParseObject(recusiveCount); + token = ParseObject(recursiveCount); break; case '[': - token = ParseArray(recusiveCount); + token = ParseArray(recursiveCount); break; default: @@ -609,15 +630,15 @@ namespace VAR.Json else { string aux = ParseString(); - if (aux.CompareTo("true") == 0) + if (aux.Equals("true")) { token = true; } - else if (aux.CompareTo("false") == 0) + else if (aux.Equals("false")) { token = false; } - else if (aux.CompareTo("null") == 0) + else if (aux.Equals("null")) { token = null; } @@ -628,12 +649,15 @@ namespace VAR.Json { _ctx.Next(); } + _tainted = true; token = null; } } + break; } + return token; } @@ -666,7 +690,7 @@ namespace VAR.Json return obj; } - private static JsonParser _currentInstance = null; + private static JsonParser _currentInstance; public static object ParseText(string text, params Type[] knownTypes) { @@ -674,6 +698,7 @@ namespace VAR.Json { _currentInstance = new JsonParser(); } + _currentInstance.KnownTypes.Clear(); _currentInstance.KnownTypes.AddRange(knownTypes); return _currentInstance.Parse(text); diff --git a/VAR.Json/JsonWriter.cs b/VAR.Json/JsonWriter.cs index 7734d65..1c8ab55 100644 --- a/VAR.Json/JsonWriter.cs +++ b/VAR.Json/JsonWriter.cs @@ -2,34 +2,39 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; namespace VAR.Json { public class JsonWriterConfiguration { - private bool _indent; - public bool Indent { get { return _indent; } } + private readonly bool _indent; - private bool _useTabForIndent; - public bool UseTabForIndent { get { return _useTabForIndent; } } + public bool Indent => _indent; - private int _indentChars; - public int IndentChars { get { return _indentChars; } } + private readonly bool _useTabForIndent; - private int _indentThresold; - public int IndentThresold { get { return _indentThresold; } } + public bool UseTabForIndent => _useTabForIndent; + + private readonly int _indentChars; + + public int IndentChars => _indentChars; + + private readonly int _indentThreshold; + + public int IndentThreshold => _indentThreshold; public JsonWriterConfiguration( bool indent = false, bool useTabForIndent = false, int indentChars = 4, - int indentThresold = 3) + int indentThreshold = 3) { _indent = indent; _useTabForIndent = useTabForIndent; _indentChars = indentChars; - _indentThresold = indentThresold; + _indentThreshold = indentThreshold; } public bool Equals(JsonWriterConfiguration other) @@ -38,22 +43,24 @@ namespace VAR.Json other.Indent == Indent && other.UseTabForIndent == UseTabForIndent && other.IndentChars == IndentChars && - other.IndentThresold == IndentThresold && + other.IndentThreshold == IndentThreshold && true; } public override bool Equals(object other) { - if (other is JsonWriterConfiguration) + if (other is JsonWriterConfiguration configuration) { - return Equals(other as JsonWriterConfiguration); + return Equals(configuration); } + return false; } public override int GetHashCode() { - return _indent.GetHashCode() ^ _useTabForIndent.GetHashCode() ^ _indentChars.GetHashCode() ^ _indentThresold.GetHashCode(); + return _indent.GetHashCode() ^ _useTabForIndent.GetHashCode() ^ _indentChars.GetHashCode() ^ + _indentThreshold.GetHashCode(); } } @@ -61,7 +68,7 @@ namespace VAR.Json { #region Declarations - private JsonWriterConfiguration _config = null; + private readonly JsonWriterConfiguration _config; #endregion Declarations @@ -69,11 +76,7 @@ namespace VAR.Json public JsonWriter(JsonWriterConfiguration config = null) { - _config = config; - if (_config == null) - { - _config = new JsonWriterConfiguration(); - } + _config = config ?? new JsonWriterConfiguration(); } #endregion Creator @@ -86,6 +89,7 @@ namespace VAR.Json { return true; } + if ( (obj is float) || (obj is double) || @@ -98,6 +102,7 @@ namespace VAR.Json { return true; } + return false; } @@ -107,6 +112,7 @@ namespace VAR.Json { return; } + textWriter.Write('\n'); if (_config.UseTabForIndent) { @@ -122,11 +128,10 @@ namespace VAR.Json private void WriteString(TextWriter textWriter, string str) { textWriter.Write('"'); - char c; int n = str.Length; for (int i = 0; i < n; i++) { - c = str[i]; + char c = str[i]; if (c == '"') { textWriter.Write("\\\""); } else if (c == '\\') { textWriter.Write("\\\\"); } else if (c == '/') { textWriter.Write("\\/"); } @@ -138,6 +143,7 @@ namespace VAR.Json else if (c < 32 || c >= 127) { textWriter.Write("\\u{0:X04}", (int)c); } else { textWriter.Write(c); } } + textWriter.Write('"'); } @@ -159,43 +165,41 @@ namespace VAR.Json // Numbers textWriter.Write(obj.ToString()); } - else if (obj is string) - { - // Strings - WriteString(textWriter, (string)obj); - } - else if (obj is bool) - { - // Booleans - textWriter.Write(((bool)obj) ? "true" : "false"); - } - else if (obj is DateTime) - { - // DateTime - textWriter.Write('"'); - textWriter.Write(((DateTime)obj).ToString("yyyy-MM-ddTHH:mm:ss")); - textWriter.Write('"'); - } - else if (obj is IDictionary) - { - // Objects - WriteObject(textWriter, obj, parentLevels); - } - else if (obj is IEnumerable) - { - // Array/List - WriteList(textWriter, obj, parentLevels); - } else - { - // Reflected object - WriteReflectedObject(textWriter, obj, parentLevels); - } + switch (obj) + { + case string valString: + // Strings + WriteString(textWriter, valString); + break; + case bool valBool: + // Booleans + textWriter.Write(valBool ? "true" : "false"); + break; + case DateTime valDateTime: + // DateTime + textWriter.Write('"'); + textWriter.Write(valDateTime.ToString("yyyy-MM-ddTHH:mm:ss")); + textWriter.Write('"'); + break; + case IDictionary _: + // Objects + WriteObject(textWriter, obj, parentLevels); + break; + case IEnumerable _: + // Array/List + WriteList(textWriter, obj, parentLevels); + break; + default: + // Reflected object + WriteReflectedObject(textWriter, obj, parentLevels); + break; + } } private void WriteList(TextWriter textWriter, object obj, List parentLevels) { - IEnumerable list = (IEnumerable)obj; + IEnumerable list = ((IEnumerable)obj).Cast().ToList(); int n = 0; // Check if it is a leaf object @@ -206,6 +210,7 @@ namespace VAR.Json { isLeaf = false; } + n++; } @@ -219,29 +224,33 @@ namespace VAR.Json // Write array bool first = true; textWriter.Write("[ "); - if (!isLeaf || n > _config.IndentThresold) + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count + 1); } + foreach (object childObj in list) { if (!first) { textWriter.Write(", "); - if (!isLeaf || n > _config.IndentThresold) + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count + 1); } } + first = false; parentLevels.Add(obj); WriteValue(textWriter, childObj, parentLevels); parentLevels.Remove(obj); } - if (!isLeaf || n > _config.IndentThresold) + + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count); } + textWriter.Write(" ]"); } @@ -271,21 +280,23 @@ namespace VAR.Json // Write object bool first = true; textWriter.Write("{ "); - if (!isLeaf || n > _config.IndentThresold) + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count + 1); } + foreach (object key in map.Keys) { object value = map[key]; if (!first) { textWriter.Write(", "); - if (!isLeaf || n > _config.IndentThresold) + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count + 1); } } + first = false; WriteString(textWriter, Convert.ToString(key)); textWriter.Write(": "); @@ -293,10 +304,12 @@ namespace VAR.Json WriteValue(textWriter, value, parentLevels); parentLevels.Remove(obj); } - if (!isLeaf || n > _config.IndentThresold) + + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count); } + textWriter.Write(" }"); } @@ -311,6 +324,7 @@ namespace VAR.Json properties.Add(property); } + int n = properties.Count; // Empty @@ -335,10 +349,11 @@ namespace VAR.Json // Write object bool first = true; textWriter.Write("{ "); - if (!isLeaf || n > _config.IndentThresold) + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count + 1); } + foreach (PropertyInfo property in properties) { object value = null; @@ -348,14 +363,16 @@ namespace VAR.Json { value = property.GetValue(obj, null); } + if (!first) { textWriter.Write(", "); - if (!isLeaf || n > _config.IndentThresold) + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count + 1); } } + first = false; WriteString(textWriter, property.Name); textWriter.Write(": "); @@ -368,12 +385,15 @@ namespace VAR.Json { WriteValue(textWriter, null, parentLevels); } + parentLevels.Remove(obj); } - if (!isLeaf || n > _config.IndentThresold) + + if (!isLeaf || n > _config.IndentThreshold) { WriteIndent(textWriter, parentLevels.Count); } + textWriter.Write(" }"); } @@ -387,6 +407,7 @@ namespace VAR.Json { textWriter = new StringWriter(); } + WriteValue(textWriter, obj, new List()); return textWriter; } @@ -398,14 +419,15 @@ namespace VAR.Json return textWriter.ToString(); } - private static Dictionary _dictInstances = new Dictionary(); + private static readonly Dictionary _dictInstances = + new Dictionary(); public static string WriteObject(object obj, JsonWriterConfiguration config = null, bool indent = false, bool useTabForIndent = false, int indentChars = 4, - int indentThresold = 3) + int indentThreshold = 3) { JsonWriter jsonWriter = null; @@ -420,6 +442,7 @@ namespace VAR.Json { jsonWriter = _dictInstances[config]; } + return jsonWriter.Write(obj); } @@ -429,13 +452,14 @@ namespace VAR.Json pair.Key.Indent == indent && pair.Key.UseTabForIndent == useTabForIndent && pair.Key.IndentChars == indentChars && - pair.Key.IndentThresold == indentThresold && + pair.Key.IndentThreshold == indentThreshold && true) { jsonWriter = pair.Value; break; } } + if (jsonWriter != null) { return jsonWriter.Write(obj); @@ -445,7 +469,7 @@ namespace VAR.Json indent: indent, useTabForIndent: useTabForIndent, indentChars: indentChars, - indentThresold: indentThresold); + indentThreshold: indentThreshold); jsonWriter = new JsonWriter(jsonWriterConfiguration); _dictInstances.Add(jsonWriterConfiguration, jsonWriter); diff --git a/VAR.Json/ObjectActivator.cs b/VAR.Json/ObjectActivator.cs index 52d6588..3d5ec78 100644 --- a/VAR.Json/ObjectActivator.cs +++ b/VAR.Json/ObjectActivator.cs @@ -4,17 +4,12 @@ using System.Linq.Expressions; namespace VAR.Json { - public class ObjectActivator + public static class ObjectActivator { private static readonly Dictionary> _creators = new Dictionary>(); - public static Func GetLambdaNew(Type type) + private static Func GetLambdaNew(Type type) { - if (_creators.ContainsKey(type)) - { - return _creators[type]; - } - lock (_creators) { if (_creators.ContainsKey(type)) @@ -37,4 +32,4 @@ namespace VAR.Json return creator(); } } -} +} \ No newline at end of file diff --git a/VAR.Json/ParserContext.cs b/VAR.Json/ParserContext.cs index b41fd84..4d92a7a 100644 --- a/VAR.Json/ParserContext.cs +++ b/VAR.Json/ParserContext.cs @@ -1,13 +1,11 @@ -using System; - -namespace VAR.Json +namespace VAR.Json { public class ParserContext { #region Declarations - private string _text; - private int _length; + private readonly string _text; + private readonly int _length; private int _i; private int _markStart; @@ -33,10 +31,12 @@ namespace VAR.Json { _i++; } + if (AtEnd()) { return (char)0; } + return _text[_i]; } @@ -47,6 +47,7 @@ namespace VAR.Json { return (char)0; } + return _text[_i]; } diff --git a/VAR.Json/VAR.Json.csproj b/VAR.Json/VAR.Json.csproj index 9574d3e..a518a3e 100644 --- a/VAR.Json/VAR.Json.csproj +++ b/VAR.Json/VAR.Json.csproj @@ -1,31 +1,31 @@  - - netstandard2.0 - Library - true - true - - - VAR.Json - VAR.Json - 1.2.2 - .Net library for JSON parsing - VAR - VAR - Copyright © VAR 2016-2021 - false - LICENSE.txt - https://github.com/Kableado/VAR.Json - JSON;JSON Library - - - - - - - + + netstandard2.0 + Library + true + true + + + VAR.Json + VAR.Json + 1.2.2 + .Net library for JSON parsing + VAR + VAR + Copyright © VAR 2016-2022 + false + LICENSE.txt + https://github.com/Kableado/VAR.Json + JSON;JSON Library + + + + + + + \ No newline at end of file