private CBORObject ReadStringArrayMap(int type, long uadditional) { bool canonical = this.options.Ctap2Canonical; if (type == 2) // Byte string { if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger" + "\u0020than supported"); } int hint = (uadditional > Int32.MaxValue || (uadditional >> 63) != 0) ? Int32.MaxValue : (int)uadditional; byte[] data = ReadByteData(this.stream, uadditional, null); return(this.ObjectFromByteArray(data, hint)); } if (type == 3) // Text string { if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger" + "\u0020than supported"); } if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) { throw new CBORException("Premature end of data"); } var builder = new StringBuilder(); switch ( DataUtilities.ReadUtf8( this.stream, (int)uadditional, builder, false)) { case -1: throw new CBORException("Invalid UTF-8"); case -2: throw new CBORException("Premature end of data"); } CBORObject cbor = CBORObject.FromRaw(builder.ToString()); if (this.stringRefs != null) { int hint = (uadditional > Int32.MaxValue || (uadditional >> 63) != 0) ? Int32.MaxValue : (int)uadditional; this.stringRefs.AddStringIfNeeded(cbor, hint); } return(cbor); } if (type == 4) // Array { if (this.options.Ctap2Canonical && this.depth >= 4) { throw new CBORException("Depth too high in canonical CBOR"); } CBORObject cbor = CBORObject.NewArray(); if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger than" + "\u0020supported"); } if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) { throw new CBORException("Remaining data too small for array" + "\u0020length"); } ++this.depth; for (long i = 0; i < uadditional; ++i) { cbor.Add( this.ReadInternal()); } --this.depth; return(cbor); } if (type == 5) // Map, type 5 { if (this.options.Ctap2Canonical && this.depth >= 4) { throw new CBORException("Depth too high in canonical CBOR"); } CBORObject cbor = CBORObject.NewMap(); if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).ToString() + " is bigger than" + "\u0020supported"); } if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) { throw new CBORException("Remaining data too small for map" + "\u0020length"); } CBORObject lastKey = null; IComparer <CBORObject> comparer = CBORCanonical.Comparer; for (long i = 0; i < uadditional; ++i) { ++this.depth; CBORObject key = this.ReadInternal(); CBORObject value = this.ReadInternal(); --this.depth; if (this.options.Ctap2Canonical && lastKey != null) { int cmp = comparer.Compare(lastKey, key); if (cmp > 0) { throw new CBORException("Map key not in canonical order"); } else if (cmp == 0) { throw new CBORException("Duplicate map key"); } } if (!this.options.AllowDuplicateKeys) { if (cbor.ContainsKey(key)) { throw new CBORException("Duplicate key already exists"); } } lastKey = key; cbor[key] = value; } return(cbor); } return(null); }
public CBORObject ReadForFirstByte(int firstbyte) { if (this.depth > 500) { throw new CBORException("Too deeply nested"); } if (firstbyte < 0) { throw new CBORException("Premature end of data"); } if (firstbyte == 0xff) { throw new CBORException("Unexpected break code encountered"); } int type = (firstbyte >> 5) & 0x07; int additional = firstbyte & 0x1f; long uadditional; CBORObject fixedObject; if (this.options.Ctap2Canonical) { if (additional >= 0x1c) { // NOTE: Includes stop byte and indefinite length data items throw new CBORException("Invalid canonical CBOR encountered"); } // Check if this represents a fixed object (NOTE: All fixed objects // comply with CTAP2 canonical CBOR). fixedObject = CBORObject.GetFixedObject(firstbyte); if (fixedObject != null) { return(fixedObject); } if (type == 6) { throw new CBORException("Tags not allowed in canonical CBOR"); } uadditional = ReadDataLength( this.stream, firstbyte, type, type == 7); if (type == 0) { return((uadditional >> 63) != 0 ? CBORObject.FromObject(ToUnsignedEInteger(uadditional)) : CBORObject.FromObject(uadditional)); } else if (type == 1) { return((uadditional >> 63) != 0 ? CBORObject.FromObject( ToUnsignedEInteger(uadditional).Add(1).Negate()) : CBORObject.FromObject((-uadditional) - 1L)); } else if (type == 7) { if (additional < 24) { return(CBORObject.FromSimpleValue(additional)); } else if (additional == 24 && uadditional < 32) { throw new CBORException("Invalid simple value encoding"); } else if (additional == 24) { return(CBORObject.FromSimpleValue((int)uadditional)); } else if (additional == 25) { return(CBORObject.FromFloatingPointBits(uadditional, 2)); } else if (additional == 26) { return(CBORObject.FromFloatingPointBits(uadditional, 4)); } else if (additional == 27) { return(CBORObject.FromFloatingPointBits(uadditional, 8)); } } else if (type >= 2 && type <= 5) { return(this.ReadStringArrayMap(type, uadditional)); } throw new CBORException("Unexpected data encountered"); } int expectedLength = CBORObject.GetExpectedLength(firstbyte); // Data checks if (expectedLength == -1) { // if the head byte is invalid throw new CBORException("Unexpected data encountered"); } // Check if this represents a fixed object fixedObject = CBORObject.GetFixedObject(firstbyte); if (fixedObject != null) { return(fixedObject); } // Read fixed-length data byte[] data = null; if (expectedLength != 0) { data = new byte[expectedLength]; // include the first byte because GetFixedLengthObject // will assume it exists for some head bytes data[0] = unchecked ((byte)firstbyte); if (expectedLength > 1 && this.stream.Read(data, 1, expectedLength - 1) != expectedLength - 1) { throw new CBORException("Premature end of data"); } CBORObject cbor = CBORObject.GetFixedLengthObject(firstbyte, data); if (this.stringRefs != null && (type == 2 || type == 3)) { this.stringRefs.AddStringIfNeeded(cbor, expectedLength - 1); } return(cbor); } if (additional == 31) { // Indefinite-length for major types 2 to 5 (other major // types were already handled in the call to // GetFixedLengthObject). switch (type) { case 2: { // Streaming byte string using (var ms = new MemoryStream()) { // Requires same type as this one while (true) { int nextByte = this.stream.ReadByte(); if (nextByte == 0xff) { // break if the "break" code was read break; } long len = ReadDataLength(this.stream, nextByte, 2); if ((len >> 63) != 0 || len > Int32.MaxValue) { throw new CBORException("Length" + ToUnsignedEInteger(len) + " is bigger than supported "); } if (nextByte != 0x40) { // NOTE: 0x40 means the empty byte string ReadByteData(this.stream, len, ms); } } if (ms.Position > Int32.MaxValue) { throw new CBORException("Length of bytes to be streamed is bigger" + "\u0020than supported "); } data = ms.ToArray(); return(CBORObject.FromRaw(data)); } } case 3: { // Streaming text string var builder = new StringBuilder(); while (true) { int nextByte = this.stream.ReadByte(); if (nextByte == 0xff) { // break if the "break" code was read break; } long len = ReadDataLength(this.stream, nextByte, 3); if ((len >> 63) != 0 || len > Int32.MaxValue) { throw new CBORException("Length" + ToUnsignedEInteger(len) + " is bigger than supported"); } if (nextByte != 0x60) { // NOTE: 0x60 means the empty string if (PropertyMap.ExceedsKnownLength(this.stream, len)) { throw new CBORException("Premature end of data"); } switch ( DataUtilities.ReadUtf8( this.stream, (int)len, builder, false)) { case -1: throw new CBORException("Invalid UTF-8"); case -2: throw new CBORException("Premature end of data"); } } } return(CBORObject.FromRaw(builder.ToString())); } case 4: { CBORObject cbor = CBORObject.NewArray(); var vtindex = 0; // Indefinite-length array while (true) { int headByte = this.stream.ReadByte(); if (headByte < 0) { throw new CBORException("Premature end of data"); } if (headByte == 0xff) { // Break code was read break; } ++this.depth; CBORObject o = this.ReadForFirstByte( headByte); --this.depth; cbor.Add(o); ++vtindex; } return(cbor); } case 5: { CBORObject cbor = CBORObject.NewMap(); // Indefinite-length map while (true) { int headByte = this.stream.ReadByte(); if (headByte < 0) { throw new CBORException("Premature end of data"); } if (headByte == 0xff) { // Break code was read break; } ++this.depth; CBORObject key = this.ReadForFirstByte(headByte); CBORObject value = this.ReadInternal(); --this.depth; if (!this.options.AllowDuplicateKeys) { if (cbor.ContainsKey(key)) { throw new CBORException("Duplicate key already exists"); } } cbor[key] = value; } return(cbor); } default: throw new CBORException("Unexpected data encountered"); } } EInteger bigintAdditional = EInteger.Zero; uadditional = ReadDataLength(this.stream, firstbyte, type); // The following doesn't check for major types 0 and 1, // since all of them are fixed-length types and are // handled in the call to GetFixedLengthObject. if (type >= 2 && type <= 5) { return(this.ReadStringArrayMap(type, uadditional)); } if (type == 6) // Tagged item { var haveFirstByte = false; var newFirstByte = -1; if (this.options.ResolveReferences && (uadditional >> 32) == 0) { // NOTE: HandleItemTag treats only certain tags up to 256 specially this.HandleItemTag(uadditional); } ++this.depth; CBORObject o = haveFirstByte ? this.ReadForFirstByte( newFirstByte) : this.ReadInternal(); --this.depth; if ((uadditional >> 63) != 0) { return(CBORObject.FromObjectAndTag(o, ToUnsignedEInteger(uadditional))); } if (uadditional < 65536) { if (this.options.ResolveReferences) { int uaddl = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 : (int)uadditional); switch (uaddl) { case 256: // string tag this.stringRefs.Pop(); break; case 25: // stringref tag if (o.IsTagged || o.Type != CBORType.Integer) { throw new CBORException("stringref must be an unsigned" + "\u0020integer"); } return(this.stringRefs.GetString(o.AsEIntegerValue())); } } return(CBORObject.FromObjectAndTag( o, (int)uadditional)); } return(CBORObject.FromObjectAndTag( o, (EInteger)uadditional)); } throw new CBORException("Unexpected data encountered"); }
public static object TypeToObject( CBORObject objThis, Type t, CBORTypeMapper mapper, PODOptions options, int depth) { if (t.Equals(typeof(int))) { return(objThis.AsInt32()); } if (t.Equals(typeof(short))) { return(objThis.AsNumber().ToInt16Checked()); } if (t.Equals(typeof(ushort))) { return(objThis.AsUInt16Legacy()); } if (t.Equals(typeof(byte))) { return(objThis.AsByteLegacy()); } if (t.Equals(typeof(sbyte))) { return(objThis.AsSByteLegacy()); } if (t.Equals(typeof(long))) { return(objThis.AsNumber().ToInt64Checked()); } if (t.Equals(typeof(uint))) { return(objThis.AsUInt32Legacy()); } if (t.Equals(typeof(ulong))) { return(objThis.AsUInt64Legacy()); } if (t.Equals(typeof(double))) { return(objThis.AsDouble()); } if (t.Equals(typeof(decimal))) { return(objThis.AsDecimal()); } if (t.Equals(typeof(float))) { return(objThis.AsSingle()); } if (t.Equals(typeof(bool))) { return(objThis.AsBoolean()); } if (t.Equals(typeof(char))) { if (objThis.Type == CBORType.TextString) { string s = objThis.AsString(); if (s.Length != 1) { throw new CBORException("Can't convert to char"); } return(s[0]); } if (objThis.IsNumber && objThis.AsNumber().CanFitInInt32()) { int c = objThis.AsNumber().ToInt32IfExact(); if (c < 0 || c >= 0x10000) { throw new CBORException("Can't convert to char"); } return((char)c); } throw new CBORException("Can't convert to char"); } if (t.Equals(typeof(DateTime))) { return(new CBORDateConverter().FromCBORObject(objThis)); } if (t.Equals(typeof(Guid))) { return(new CBORUuidConverter().FromCBORObject(objThis)); } if (t.Equals(typeof(Uri))) { return(new CBORUriConverter().FromCBORObject(objThis)); } if (IsAssignableFrom(typeof(Enum), t)) { return(ObjectToEnum(objThis, t)); } if (IsGenericType(t)) { Type td = t.GetGenericTypeDefinition(); // Nullable types if (td.Equals(typeof(Nullable <>))) { Type nullableType = Nullable.GetUnderlyingType(t); if (objThis.IsNull) { return(Activator.CreateInstance(t)); } else { object wrappedObj = objThis.ToObject( nullableType, mapper, options, depth + 1); return(Activator.CreateInstance( t, wrappedObj)); } } } if (objThis.Type == CBORType.ByteString) { if (t.Equals(typeof(byte[]))) { byte[] bytes = objThis.GetByteString(); var byteret = new byte[bytes.Length]; Array.Copy(bytes, 0, byteret, 0, byteret.Length); return(byteret); } } if (objThis.Type == CBORType.Array) { Type objectType = typeof(object); var isList = false; object listObject = null; #if NET40 || NET20 if (IsAssignableFrom(typeof(Array), t)) { Type elementType = t.GetElementType(); Array array = Array.CreateInstance( elementType, GetDimensions(objThis)); return(FillArray( array, elementType, objThis, mapper, options, depth)); } 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 = isList && t.GetGenericArguments().Length == 1; if (isList) { objectType = t.GetGenericArguments()[0]; Type listType = typeof(List <>).MakeGenericType(objectType); listObject = Activator.CreateInstance(listType); } #else if (IsAssignableFrom(typeof(Array), t)) { Type elementType = t.GetElementType(); Array array = Array.CreateInstance( elementType, GetDimensions(objThis)); return(FillArray( array, elementType, objThis, mapper, options, depth)); } if (t.GetTypeInfo().IsGenericType) { Type td = t.GetGenericTypeDefinition(); isList = td.Equals(typeof(List <>)) || td.Equals(typeof(IList <>)) || td.Equals(typeof(ICollection <>)) || td.Equals(typeof(IEnumerable <>)); } isList = isList && t.GenericTypeArguments.Length == 1; if (isList) { objectType = t.GenericTypeArguments[0]; Type listType = typeof(List <>).MakeGenericType(objectType); listObject = Activator.CreateInstance(listType); } #endif if (listObject == null) { if (t.Equals(typeof(IList)) || t.Equals(typeof(ICollection)) || t.Equals(typeof(IEnumerable))) { listObject = new List <object>(); objectType = typeof(object); } } if (listObject != null) { System.Collections.IList ie = (System.Collections.IList)listObject; foreach (CBORObject value in objThis.Values) { ie.Add(value.ToObject(objectType, mapper, options, depth + 1)); } return(listObject); } } if (objThis.Type == CBORType.Map) { var isDict = false; Type keyType = null; Type valueType = null; object dictObject = null; #if NET40 || NET20 isDict = t.IsGenericType; if (t.IsGenericType) { Type td = t.GetGenericTypeDefinition(); isDict = td.Equals(typeof(Dictionary <,>)) || td.Equals(typeof(IDictionary <,>)); } // DebugUtility.Log("list=" + isDict); isDict = isDict && t.GetGenericArguments().Length == 2; // DebugUtility.Log("list=" + isDict); if (isDict) { keyType = t.GetGenericArguments()[0]; valueType = t.GetGenericArguments()[1]; Type listType = typeof(Dictionary <,>).MakeGenericType( keyType, valueType); dictObject = Activator.CreateInstance(listType); } #else isDict = t.GetTypeInfo().IsGenericType; if (t.GetTypeInfo().IsGenericType) { Type td = t.GetGenericTypeDefinition(); isDict = td.Equals(typeof(Dictionary <,>)) || td.Equals(typeof(IDictionary <,>)); } // DebugUtility.Log("list=" + isDict); isDict = isDict && t.GenericTypeArguments.Length == 2; // DebugUtility.Log("list=" + isDict); if (isDict) { keyType = t.GenericTypeArguments[0]; valueType = t.GenericTypeArguments[1]; Type listType = typeof(Dictionary <,>).MakeGenericType( keyType, valueType); dictObject = Activator.CreateInstance(listType); } #endif if (dictObject == null) { if (t.Equals(typeof(IDictionary))) { dictObject = new Dictionary <object, object>(); keyType = typeof(object); valueType = typeof(object); } } if (dictObject != null) { System.Collections.IDictionary idic = (System.Collections.IDictionary)dictObject; foreach (CBORObject key in objThis.Keys) { CBORObject value = objThis[key]; idic.Add( key.ToObject(keyType, mapper, options, depth + 1), value.ToObject(valueType, mapper, options, depth + 1)); } return(dictObject); } if (mapper != null) { if (!mapper.FilterTypeName(t.FullName)) { throw new CBORException("Type " + t.FullName + " not supported"); } } else { if (t.FullName != null && ( StartsWith(t.FullName, "Microsoft.Win32.") || StartsWith(t.FullName, "System.IO."))) { throw new CBORException("Type " + t.FullName + " not supported"); } if (StartsWith(t.FullName, "System.") && !HasCustomAttribute(t, "System.SerializableAttribute")) { throw new CBORException("Type " + t.FullName + " not supported"); } } var values = new List <KeyValuePair <string, CBORObject> >(); var propNames = PropertyMap.GetPropertyNames( t, options != null ? options.UseCamelCase : true); foreach (string key in propNames) { if (objThis.ContainsKey(key)) { CBORObject cborValue = objThis[key]; var dict = new KeyValuePair <string, CBORObject>( key, cborValue); values.Add(dict); } } return(PropertyMap.ObjectWithProperties( t, values, mapper, options, depth)); } else { throw new CBORException(); } }