예제 #1
0
        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);
        }
예제 #2
0
        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");
        }
예제 #3
0
        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();
            }
        }