diff --git a/CBOR.nuspec b/CBOR.nuspec index cf4af62c..32d16e51 100644 --- a/CBOR.nuspec +++ b/CBOR.nuspec @@ -1,5 +1,10 @@ 4.1.0PeterO.CborfalseVersion 4.1: +>4.2.0PeterO.CborfalseVersion 4.2: -- JSONOptions string constructor now sets ReplaceSurrogates to false by default (previously, it was inadvertently true).CC0-1.0https://github.com/peteroupc/CBORPeter OccilA C# implementation of Concise Binary Object Representation (CBOR), a general-purpose binary data format defined in RFC 7049.Peter OccilCBOR (Concise Binary Object Representation)cbor data serialization binary json +- Some arithmetic methods in CBORNumber do basic overflow checks. +- Add char array and byte array overloads to ParseJSONNumber +- Support implementations of IList in CBORObject deserialization +- Internally, the code avoids storing doubles (64-bit floating-point numbers) directly in CBORNumbers, uses sorted maps rather than hash tables in some CBOR objects, and can now store text strings as UTF-8 byte arrays. This could help avoid unnecessary string conversions in many case. +- Bug fixes and performance improvements +- Now uses Numbers library version 1.7.3CC0-1.0https://github.com/peteroupc/CBORPeter OccilA C# implementation of Concise Binary Object Representation (CBOR), a general-purpose binary data format defined in RFC 7049.Peter OccilCBOR (Concise Binary Object Representation)cbor data serialization binary json \ No newline at end of file diff --git a/CBOR/PeterO/Cbor/PropertyMap.cs b/CBOR/PeterO/Cbor/PropertyMap.cs index 844fc415..647e1029 100644 --- a/CBOR/PeterO/Cbor/PropertyMap.cs +++ b/CBOR/PeterO/Cbor/PropertyMap.cs @@ -101,12 +101,12 @@ public void SetValue(object obj, object value) { } #if NET20 || NET40 - public static bool HasUsableGetter (PropertyInfo pi) { + public static bool HasUsableGetter(PropertyInfo pi) { return pi != null && pi.CanRead && !pi.GetGetMethod().IsStatic && pi.GetGetMethod().IsPublic; } - public static bool HasUsableSetter (PropertyInfo pi) { + public static bool HasUsableSetter(PropertyInfo pi) { return pi != null && pi.CanWrite && !pi.GetSetMethod().IsStatic && pi.GetSetMethod().IsPublic; } @@ -166,47 +166,47 @@ public MemberInfo Prop { } #if NET40 || NET20 - private static bool IsGenericType (Type type) { + private static bool IsGenericType(Type type) { return type.IsGenericType; } - private static bool IsClassOrValueType (Type type) { + private static bool IsClassOrValueType(Type type) { return type.IsClass || type.IsValueType; } - private static Type FirstGenericArgument (Type type) { + private static Type FirstGenericArgument(Type type) { return type.GetGenericArguments()[0]; } - private static IEnumerable GetTypeProperties (Type t) { - return t.GetProperties (BindingFlags.Public | + private static IEnumerable GetTypeProperties(Type t) { + return t.GetProperties(BindingFlags.Public | BindingFlags.Instance); } - private static IEnumerable GetTypeFields (Type t) { - return t.GetFields (BindingFlags.Public | BindingFlags.Instance); + private static IEnumerable GetTypeFields(Type t) { + return t.GetFields(BindingFlags.Public | BindingFlags.Instance); } - private static IEnumerable GetTypeInterfaces (Type t) { + private static IEnumerable GetTypeInterfaces(Type t) { return t.GetInterfaces(); } - private static bool IsAssignableFrom (Type superType, Type subType) { - return superType.IsAssignableFrom (subType); + private static bool IsAssignableFrom(Type superType, Type subType) { + return superType.IsAssignableFrom(subType); } private static MethodInfo GetTypeMethod( Type t, string name, Type[] parameters) { - return t.GetMethod (name, parameters); + return t.GetMethod(name, parameters); } private static bool HasCustomAttribute( Type t, string name) { - foreach (var attr in t.GetCustomAttributes (false)) { - if (attr.GetType().FullName.Equals (name, + foreach (var attr in t.GetCustomAttributes(false)) { + if (attr.GetType().FullName.Equals(name, StringComparison.Ordinal)) { return true; } @@ -784,11 +784,11 @@ public static object TypeToObject( object listObject = null; object genericListObject = null; #if NET40 || NET20 - if (IsAssignableFrom (typeof(Array), t)) { + if (IsAssignableFrom(typeof(Array), t)) { Type elementType = t.GetElementType(); Array array = Array.CreateInstance( elementType, - GetDimensions (objThis)); + GetDimensions(objThis)); return FillArray( array, elementType, @@ -799,15 +799,15 @@ public static object TypeToObject( } if (t.IsGenericType) { Type td = t.GetGenericTypeDefinition(); - isList = td.Equals (typeof(List<>)) || td.Equals (typeof(IList<>)) || - td.Equals (typeof(ICollection<>)) || - td.Equals (typeof(IEnumerable<>)); + isList = td.Equals(typeof(List<>)) || td.Equals(typeof(IList<>)) || + td.Equals(typeof(ICollection<>)) || + td.Equals(typeof(IEnumerable<>)); } isList = isList && t.GetGenericArguments().Length == 1; if (isList) { objectType = t.GetGenericArguments()[0]; - Type listType = typeof(List<>).MakeGenericType (objectType); - listObject = Activator.CreateInstance (listType); + Type listType = typeof(List<>).MakeGenericType(objectType); + listObject = Activator.CreateInstance(listType); } #else if (IsAssignableFrom(typeof(Array), t)) { @@ -896,8 +896,8 @@ public static object TypeToObject( isDict = t.IsGenericType; if (t.IsGenericType) { Type td = t.GetGenericTypeDefinition(); - isDict = td.Equals (typeof(Dictionary<,>)) || - td.Equals (typeof(IDictionary<,>)); + isDict = td.Equals(typeof(Dictionary<,>)) || + td.Equals(typeof(IDictionary<,>)); } // DebugUtility.Log("list=" + isDict); isDict = isDict && t.GetGenericArguments().Length == 2; @@ -908,7 +908,7 @@ public static object TypeToObject( Type listType = typeof(Dictionary<,>).MakeGenericType( keyType, valueType); - dictObject = Activator.CreateInstance (listType); + dictObject = Activator.CreateInstance(listType); } #else isDict = t.GetTypeInfo().IsGenericType; diff --git a/CBOR20/Properties/AssemblyInfo.cs b/CBOR20/Properties/AssemblyInfo.cs index 181ef7de..b3aea676 100644 --- a/CBOR20/Properties/AssemblyInfo.cs +++ b/CBOR20/Properties/AssemblyInfo.cs @@ -1,8 +1,8 @@ using System.Reflection; [assembly: System.CLSCompliant(true)] -[assembly: AssemblyInformationalVersion("4.1.0")] -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] [assembly: AssemblyProduct("CBOR (Concise Binary Object Representati" + "on)")] [assembly: AssemblyTitle("CBOR (Concise Binary Object Representati" + diff --git a/CBOR40/Properties/AssemblyInfo.cs b/CBOR40/Properties/AssemblyInfo.cs index 181ef7de..b3aea676 100644 --- a/CBOR40/Properties/AssemblyInfo.cs +++ b/CBOR40/Properties/AssemblyInfo.cs @@ -1,8 +1,8 @@ using System.Reflection; [assembly: System.CLSCompliant(true)] -[assembly: AssemblyInformationalVersion("4.1.0")] -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] [assembly: AssemblyProduct("CBOR (Concise Binary Object Representati" + "on)")] [assembly: AssemblyTitle("CBOR (Concise Binary Object Representati" + diff --git a/CBORTest/CBORExtraTest.cs b/CBORTest/CBORExtraTest.cs index 647a58d8..7c58d67d 100644 --- a/CBORTest/CBORExtraTest.cs +++ b/CBORTest/CBORExtraTest.cs @@ -172,13 +172,25 @@ public enum CustomBits { C = 4, } + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "Microsoft.Design", + "CA1034", + Justification = "Testing whether serialization works " + "on nested public types")] public sealed class CustomCollectionContainer { + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "Microsoft.Usage", + "CA2227", + Justification = "Testing whether serialization works " + "on public properties of nested public types")] public CustomCollection CList { get; set; } } + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "Microsoft.Design", + "CA1034", + Justification = "Testing whether serialization works " + "on nested public types")] public sealed class CustomCollection : IList { private List w = new List(); diff --git a/CBORTest/CBORObjectTest.cs b/CBORTest/CBORObjectTest.cs index 9aa29b5b..d39968d8 100644 --- a/CBORTest/CBORObjectTest.cs +++ b/CBORTest/CBORObjectTest.cs @@ -7317,7 +7317,6 @@ public void TestFromJsonStringLongSpecific1() { } [Test] - [Timeout(5000)] public void TestFromJsonStringFastCases() { var op = new JSONOptions("numberconversion=double"); Assert.AreEqual( diff --git a/CBORTest/CBORTest.cs b/CBORTest/CBORTest.cs index 171e41d6..10bf5e43 100644 --- a/CBORTest/CBORTest.cs +++ b/CBORTest/CBORTest.cs @@ -2240,7 +2240,6 @@ private static string ToByteArrayStringFrom(byte[] array, int pos) { public void TestRandomNonsense() { var rand = new RandomGenerator(); for (var i = 0; i < 1000; ++i) { - Console.WriteLine(i + ": " + DateTime.UtcNow); var array = new byte[rand.UniformInt(100000) + 1]; rand.GetBytes(array, 0, array.Length); TestRandomOne(array); @@ -2274,16 +2273,13 @@ public static void TestRandomOne(byte[] array) { long oldPos = inputStream.Position; o = CBORObject.Read(inputStream); long cborlen = inputStream.Position - oldPos; - if (cborlen > 3000) { - Console.WriteLine("pos=" + inputStream.Position + " of " + -inputStream.Length + ", cborlen=" + cborlen); - } + // if (cborlen > 3000) { + // Console.WriteLine("pos=" + inputStream.Position + " of " + + // inputStream.Length + ", cborlen=" + cborlen); + // } byte[] encodedBytes = (o == null) ? null : o.EncodeToBytes(); try { CBORObject.DecodeFromBytes(encodedBytes); - if (cborlen > 3000) { - Console.WriteLine("end DecodeFromBytes"); - } } catch (Exception ex) { throw new InvalidOperationException(ex.Message, ex); } @@ -2294,29 +2290,14 @@ public static void TestRandomOne(byte[] array) { } if (o != null) { try { -if (cborlen > 3000) { - Console.WriteLine("toJSONString " + DateTime.UtcNow); - } jsonString = o.ToJSONString(); -if (cborlen > 3000) { - Console.WriteLine("jsonStringLen = " + jsonString.Length); - } } catch (CBORException ex) { Console.WriteLine(ex.Message); jsonString = String.Empty; } if (jsonString.Length > 0) { - if (cborlen > 3000) { - Console.WriteLine("fromJSONString " + DateTime.UtcNow); - } CBORObject.FromJSONString(jsonString); - if (cborlen > 3000) { - Console.WriteLine("writeToJSON " + DateTime.UtcNow); - } TestWriteToJSON(o); - if (cborlen > 3000) { - Console.WriteLine("endJSON " + DateTime.UtcNow); - } } } } catch (Exception ex) { @@ -2740,66 +2721,66 @@ public void TestAsNumberAddSubtract() { public static bool TestAsNumberMultiplyDivideOne( CBORObject o1, CBORObject o2) { - if (o1 == null) { - throw new ArgumentNullException(nameof(o1)); - } - if (o2 == null) { - throw new ArgumentNullException(nameof(o2)); - } - if (!o1.IsNumber || !o2.IsNumber) { - return false; - } - byte[] eb1 = o1.EncodeToBytes(); - byte[] eb2 = o2.EncodeToBytes(); - CBORTestCommon.AssertRoundTrip(o1); - CBORTestCommon.AssertRoundTrip(o2); - CBORNumber on1 = o1.AsNumber(); - CBORNumber on2 = o2.AsNumber(); - CBORNumber onSum = null; - try { - onSum = on1.Multiply(on2); - } catch (OutOfMemoryException) { - return false; - } - if (!onSum.IsFinite()) { - // Console.WriteLine("on1=" + o1); - // Console.WriteLine("on2=" + o2); - return false; - } - // Console.WriteLine(i+""); - // Console.WriteLine(i+" "+Chop(o1.ToString())); - // Console.WriteLine(i+" "+Chop(o2.ToString())); - // Console.WriteLine(i + " " + Chop(onSum.ToString())); - if (!onSum.IsFinite()) { - Assert.Fail("onSum is not finite\n" + - "o1=" + TestCommon.ToByteArrayString(eb1) + "\n" + - "o2=" + TestCommon.ToByteArrayString(eb2) + "\n"); - } - CBORNumber on2a = onSum.Divide(on1); - // NOTE: Ignore if divisor is zero - if (!on1.IsZero() && !on2a.IsFinite()) { - Assert.Fail("on2a is not finite\n" + - "o1=" + TestCommon.ToByteArrayString(eb1) + "\n" + - "o2=" + TestCommon.ToByteArrayString(eb2) + "\n"); - } - if (!on1.IsZero() && !on2.IsZero()) { - VerifyEqual(on2a, on2, o1, o2); - } - CBORNumber on1a = onSum.Divide(on2); - // NOTE: Ignore if divisor is zero - if (!on2.IsZero() && !on1a.IsFinite()) { - Assert.Fail("on1a is not finite\n" + - "o1=" + on1 + "\n" + "o2=" + on2 + "\n" + - "{\nbyte[] bytes1 = " + TestCommon.ToByteArrayString(eb1) + ";\n" + - "byte[] bytes2 =" + TestCommon.ToByteArrayString(eb2) + ";\n" + - "TestAsNumberMultiplyDivideOne(\nCBORObject.D" + - "ecodeFromBytes(bytes1),\n" + - "CBORObject.DecodeFromBytes(bytes2));\n}\n"); - } - if (!on1.IsZero() && !on2.IsZero()) { - VerifyEqual(on1a, on1, o1, o2); - } - return true; + if (o1 == null) { + throw new ArgumentNullException(nameof(o1)); + } + if (o2 == null) { + throw new ArgumentNullException(nameof(o2)); + } + if (!o1.IsNumber || !o2.IsNumber) { + return false; + } + byte[] eb1 = o1.EncodeToBytes(); + byte[] eb2 = o2.EncodeToBytes(); + CBORTestCommon.AssertRoundTrip(o1); + CBORTestCommon.AssertRoundTrip(o2); + CBORNumber on1 = o1.AsNumber(); + CBORNumber on2 = o2.AsNumber(); + CBORNumber onSum = null; + try { + onSum = on1.Multiply(on2); + } catch (OutOfMemoryException) { + return false; + } + if (!onSum.IsFinite()) { + // Console.WriteLine("on1=" + o1); + // Console.WriteLine("on2=" + o2); + return false; + } + // Console.WriteLine(i+""); + // Console.WriteLine(i+" "+Chop(o1.ToString())); + // Console.WriteLine(i+" "+Chop(o2.ToString())); + // Console.WriteLine(i + " " + Chop(onSum.ToString())); + if (!onSum.IsFinite()) { + Assert.Fail("onSum is not finite\n" + + "o1=" + TestCommon.ToByteArrayString(eb1) + "\n" + + "o2=" + TestCommon.ToByteArrayString(eb2) + "\n"); + } + CBORNumber on2a = onSum.Divide(on1); + // NOTE: Ignore if divisor is zero + if (!on1.IsZero() && !on2a.IsFinite()) { + Assert.Fail("on2a is not finite\n" + + "o1=" + TestCommon.ToByteArrayString(eb1) + "\n" + + "o2=" + TestCommon.ToByteArrayString(eb2) + "\n"); + } + if (!on1.IsZero() && !on2.IsZero()) { + VerifyEqual(on2a, on2, o1, o2); + } + CBORNumber on1a = onSum.Divide(on2); + // NOTE: Ignore if divisor is zero + if (!on2.IsZero() && !on1a.IsFinite()) { + Assert.Fail("on1a is not finite\n" + + "o1=" + on1 + "\n" + "o2=" + on2 + "\n" + + "{\nbyte[] bytes1 = " + TestCommon.ToByteArrayString(eb1) + ";\n" + + "byte[] bytes2 =" + TestCommon.ToByteArrayString(eb2) + ";\n" + + "TestAsNumberMultiplyDivideOne(\nCBORObject.D" + + "ecodeFromBytes(bytes1),\n" + + "CBORObject.DecodeFromBytes(bytes2));\n}\n"); + } + if (!on1.IsZero() && !on2.IsZero()) { + VerifyEqual(on1a, on1, o1, o2); + } + return true; } [Test] diff --git a/CBORTest/JSONPointer.cs b/CBORTest/JSONPointer.cs index d0b7f50f..8d326600 100644 --- a/CBORTest/JSONPointer.cs +++ b/CBORTest/JSONPointer.cs @@ -343,6 +343,30 @@ public static IDictionary GetPointersWithKey( return list; } + private static String Replace(string str, char c, string srep) { + var j = -1; + for (int i = 0; i < str.Length; ++i) { + if (str[i] == c) { + j = i; + break; + } + } + if (j == -1) { + return str; + } + var sb = new StringBuilder(); + sb.Append(str.Substring(0, j)); + sb.Append(srep); + for (int i = j + 1; i < str.Length; ++i) { + if (str[i] == c) { + sb.Append(srep); + } else { + sb.Append(str[i]); + } + } + return sb.ToString(); + } + private static void GetPointersWithKey( CBORObject root, string keyToFind, @@ -365,8 +389,8 @@ private static void GetPointersWithKey( // Search the key's values foreach (CBORObject key in rootObj.Keys) { string ptrkey = key.AsString(); - ptrkey = ptrkey.Replace("~", "~0"); - ptrkey = ptrkey.Replace("/", "~1"); + ptrkey = Replace(ptrkey, '~', "~0"); + ptrkey = Replace(ptrkey, '/', "~1"); GetPointersWithKey( rootObj[key], keyToFind, diff --git a/CBORTest/RandomObjects.cs b/CBORTest/RandomObjects.cs index 877c2ffe..9e55c069 100644 --- a/CBORTest/RandomObjects.cs +++ b/CBORTest/RandomObjects.cs @@ -390,18 +390,18 @@ public static EFloat CloseToPowerOfTwo(IRandomGenExtended rg) { throw new ArgumentNullException(nameof(rg)); } int pwr = (rg.GetInt32(100) < 80) ? IntInRange(rg, -20, 20) : -IntInRange(rg, -300, 300); + IntInRange(rg, -300, 300); int pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : -IntInRange(rg, 2, 300)); + IntInRange(rg, 2, 300)); EFloat ef = null; - ef = (rg.GetInt32(2) == 0) ? (EFloat.Create(1, - pwr).Add(EFloat.Create(1, pwr2))) : (EFloat.Create(1, - pwr).Subtract(EFloat.Create(1, pwr2))); + ef = (rg.GetInt32(2) == 0) ? EFloat.Create(1, + pwr).Add(EFloat.Create(1, pwr2)) : EFloat.Create(1, + pwr).Subtract(EFloat.Create(1, pwr2)); if (rg.GetInt32(10) == 0) { pwr2 = pwr - (rg.GetInt32(100) < 80 ? IntInRange(rg, 51, 61) : -IntInRange(rg, 2, 300)); + IntInRange(rg, 2, 300)); ef = (rg.GetInt32(2) == 0) ? ef.Add(EFloat.Create(1, pwr2)) : -ef.Subtract(EFloat.Create(1, pwr2)); + ef.Subtract(EFloat.Create(1, pwr2)); } return ef; }