CalculateHash() static private method

static private CalculateHash ( UInt32 table, UInt32 seed, byte buffer, int start, int size ) : UInt32
table System.UInt32
seed System.UInt32
buffer byte
start int
size int
return System.UInt32
        private static bool TryDeserializeObject(Type type, XmlReader reader, object existingInstance, out object result)
        {
            #region Local Methods to reduce complexity

            bool TryDeserializeKeyValue(ref TryDeserializeObjectContext ctx)
            {
                if (ctx.Type?.IsGenericTypeOf(Reflector.KeyValuePairType) != true)
                {
                    return(false);
                }

                bool   keyRead   = false;
                bool   valueRead = false;
                object key       = null;
                object value     = null;

                while (true)
                {
                    ReadToNodeType(ctx.Reader, XmlNodeType.Element, XmlNodeType.EndElement);
                    switch (ctx.Reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (ctx.Reader.Name)
                        {
                        case nameof(KeyValuePair <_, _> .Key):
                            if (keyRead)
                            {
                                Throw.ArgumentException(Res.XmlSerializationMultipleKeys);
                            }

                            keyRead = true;
                            string attrType = ctx.Reader[XmlSerializer.AttributeType];
                            Type   keyType  = attrType != null?Reflector.ResolveType(attrType) : ctx.Type.GetGenericArguments()[0];

                            if (!TryDeserializeObject(keyType, ctx.Reader, null, out key))
                            {
                                if (attrType != null && keyType == null)
                                {
                                    Throw.ReflectionException(Res.XmlSerializationCannotResolveType(attrType));
                                }
                                Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(keyType));
                            }
                            break;

                        case nameof(KeyValuePair <_, _> .Value):
                            if (valueRead)
                            {
                                Throw.ArgumentException(Res.XmlSerializationMultipleValues);
                            }

                            valueRead = true;
                            attrType  = ctx.Reader[XmlSerializer.AttributeType];
                            Type valueType = attrType != null?Reflector.ResolveType(attrType) : ctx.Type.GetGenericArguments()[1];

                            if (!TryDeserializeObject(valueType, ctx.Reader, null, out value))
                            {
                                if (attrType != null && valueType == null)
                                {
                                    Throw.ReflectionException(Res.XmlSerializationCannotResolveType(attrType));
                                }
                                Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(valueType));
                            }
                            break;

                        default:
                            Throw.ArgumentException(Res.XmlSerializationUnexpectedElement(ctx.Reader.Name));
                            break;
                        }
                        break;

                    case XmlNodeType.EndElement:
                        // end of KeyValue: checking whether both key and value have been read
                        if (!keyRead)
                        {
                            Throw.ArgumentException(Res.XmlSerializationKeyValueMissingKey);
                        }
                        if (!valueRead)
                        {
                            Throw.ArgumentException(Res.XmlSerializationKeyValueMissingValue);
                        }

                        ctx.Result = Activator.CreateInstance(ctx.Type);
                        Accessors.SetKeyValue(ctx.Result, key, value);
                        return(true);
                    }
                }
            }

            void DeserializeBinary(ref TryDeserializeObjectContext ctx)
            {
                if (ctx.Reader.IsEmptyElement)
                {
                    return;
                }

                string attrCrc = ctx.Reader[XmlSerializer.AttributeCrc];

                ReadToNodeType(ctx.Reader, XmlNodeType.Text);
                byte[] data = Convert.FromBase64String(ctx.Reader.Value);
                if (attrCrc != null)
                {
                    if (Crc32.CalculateHash(data).ToString("X8", CultureInfo.InvariantCulture) != attrCrc)
                    {
                        Throw.ArgumentException(Res.XmlSerializationCrcError);
                    }
                }

                ctx.Result = BinarySerializer.Deserialize(data);
                ReadToNodeType(ctx.Reader, XmlNodeType.EndElement);
            }

            bool TryDeserializeComplexObject(ref TryDeserializeObjectContext ctx)
            {
                if (ctx.Type == null || ctx.Reader.IsEmptyElement)
                {
                    return(false);
                }

                // 1.) array (both existing and new)
                if (ctx.Type.IsArray)
                {
                    ctx.Result = DeserializeArray(ctx.ExistingInstance as Array, ctx.Type.GetElementType(), ctx.Reader, true);
                    return(true);
                }

                // 2.) existing read-write collection
                if (ctx.Type.IsReadWriteCollection(ctx.ExistingInstance))
                {
                    DeserializeContent(ctx.Reader, ctx.ExistingInstance);
                    ctx.Result = ctx.ExistingInstance;
                    return(true);
                }

                bool isCollection = ctx.Type.IsSupportedCollectionForReflection(out var defaultCtor, out var collectionCtor, out var elementType, out bool isDictionary);

                // 3.) New collection by collectionCtor (only if there is no defaultCtor)
                if (isCollection && defaultCtor == null && !ctx.Type.IsValueType)
                {
                    ctx.Result = DeserializeContentByInitializerCollection(ctx.Reader, collectionCtor, elementType, isDictionary);
                    return(true);
                }

                ctx.Result = ctx.ExistingInstance ?? (ctx.Type.CanBeCreatedWithoutParameters()
                    ? ctx.Type.IsValueType ? Activator.CreateInstance(ctx.Type) : CreateInstanceAccessor.GetAccessor(ctx.Type).CreateInstance()
                    : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(ctx.Type)));

                // 4.) New collection by collectionCtor again (there IS defaultCtor but the new instance is read-only so falling back to collectionCtor)
                if (isCollection && !ctx.Type.IsReadWriteCollection(ctx.Result))
                {
                    if (collectionCtor != null)
                    {
                        ctx.Result = DeserializeContentByInitializerCollection(ctx.Reader, collectionCtor, elementType, isDictionary);
                        return(true);
                    }

                    Throw.SerializationException(Res.XmlSerializationCannotDeserializeReadOnlyCollection(ctx.Type));
                }

                // 5.) Newly created collection or any other object (both existing and new)
                DeserializeContent(ctx.Reader, ctx.Result);
                return(true);
            }

            #endregion

            // null value
            if (reader.IsEmptyElement && (type == null || !type.IsValueType || type.IsNullable()))
            {
                result = null;
                return(true);
            }

            if (type != null && type.IsNullable())
            {
                type = Nullable.GetUnderlyingType(type);
            }

            // a.) If type can be natively parsed, parsing from string
            if (type != null && type.CanBeParsedNatively())
            {
                string value = ReadStringValue(reader);
                result = value.Parse(type);
                return(true);
            }

            // b.) Deserialize IXmlSerializable
            string format = reader[XmlSerializer.AttributeFormat];
            if (type != null && format == XmlSerializer.AttributeValueCustom)
            {
                object instance = existingInstance ?? (type.CanBeCreatedWithoutParameters()
                    ? type.IsValueType ? Activator.CreateInstance(type) : CreateInstanceAccessor.GetAccessor(type).CreateInstance()
                    : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(type)));
                if (!(instance is IXmlSerializable xmlSerializable))
                {
                    result = default;
                    Throw.ArgumentException(Res.XmlSerializationNotAnIXmlSerializable(type));
                    return(default);
Ejemplo n.º 2
0
        /// <summary>
        /// Serializing a collection by XmlWriter
        /// </summary>
        private void SerializeCollection(IEnumerable collection, Type elementType, bool typeNeeded, XmlWriter writer, DesignerSerializationVisibility visibility)
        {
            if (collection == null)
            {
                return;
            }

            // array collection
            if (collection is Array array)
            {
                if (typeNeeded)
                {
                    writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(collection.GetType()));
                }

                // multidimensional or nonzero-based array
                if (array.Rank > 1 || array.GetLowerBound(0) != 0)
                {
                    StringBuilder dim = new StringBuilder();
                    for (int i = 0; i < array.Rank; i++)
                    {
                        int low;
                        if ((low = array.GetLowerBound(i)) != 0)
                        {
                            dim.Append(low + ".." + (low + array.GetLength(i) - 1));
                        }
                        else
                        {
                            dim.Append(array.GetLength(i));
                        }

                        if (i < array.Rank - 1)
                        {
                            dim.Append(',');
                        }
                    }

                    writer.WriteAttributeString(XmlSerializer.AttributeDim, dim.ToString());
                }
                else
                {
                    writer.WriteAttributeString(XmlSerializer.AttributeLength, array.Length.ToString(CultureInfo.InvariantCulture));
                }

                if (array.Length == 0)
                {
                    // signing that collection is not null - now it will be at least <Collection></Collection> instead of <Collection />
                    writer.WriteString(String.Empty);
                    return;
                }

                // array of a primitive type
                if (elementType.IsPrimitive && (Options & XmlSerializationOptions.CompactSerializationOfPrimitiveArrays) != XmlSerializationOptions.None)
                {
                    byte[] data = new byte[Buffer.ByteLength(array)];
                    Buffer.BlockCopy(array, 0, data, 0, data.Length);
                    if ((Options & XmlSerializationOptions.OmitCrcAttribute) == XmlSerializationOptions.None)
                    {
                        writer.WriteAttributeString(XmlSerializer.AttributeCrc, Crc32.CalculateHash(data).ToString("X8", CultureInfo.InvariantCulture));
                    }
                    writer.WriteString(Convert.ToBase64String(data));

                    return;
                }

                // non-primitive type array or compact serialization is not enabled
                if (elementType.IsPointer)
                {
                    Throw.NotSupportedException(Res.SerializationPointerArrayTypeNotSupported(collection.GetType()));
                }
                foreach (var item in array)
                {
                    writer.WriteStartElement(XmlSerializer.ElementItem);
                    if (item == null)
                    {
                        writer.WriteEndElement();
                    }
                    else
                    {
                        SerializeObject(item, !elementType.IsSealed && item.GetType() != elementType, writer, visibility);
                        writer.WriteFullEndElement();
                    }
                }

                return;
            }

            // non-array collection
            if (typeNeeded)
            {
                writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(collection.GetType()));
            }

            // serializing main properties first
            SerializeMembers(collection, writer, visibility);

            // serializing items
            foreach (var item in collection)
            {
                writer.WriteStartElement(XmlSerializer.ElementItem);
                if (item == null)
                {
                    writer.WriteEndElement();
                }
                else
                {
                    SerializeObject(item, !elementType.IsSealed && item.GetType() != elementType, writer, visibility);
                    writer.WriteFullEndElement();
                }
            }
        }
        private static bool TryDeserializeObject(Type type, XElement element, object existingInstance, out object result)
        {
            #region Local Methods to reduce complexity

            bool TryDeserializeKeyValue(ref TryDeserializeObjectContext ctx)
            {
                if (ctx.Type?.IsGenericTypeOf(Reflector.KeyValuePairType) == true)
                {
                    // key
                    XElement xItem = ctx.Element.Element(nameof(KeyValuePair <_, _> .Key));
                    if (xItem == null)
                    {
                        Throw.ArgumentException(Res.XmlSerializationKeyValueMissingKey);
                    }
                    XAttribute xType   = xItem.Attribute(XmlSerializer.AttributeType);
                    Type       keyType = xType != null?Reflector.ResolveType(xType.Value) : ctx.Type.GetGenericArguments()[0];

                    if (!TryDeserializeObject(keyType, xItem, null, out object key))
                    {
                        if (xType != null && keyType == null)
                        {
                            Throw.ReflectionException(Res.XmlSerializationCannotResolveType(xType.Value));
                        }
                        Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(keyType));
                    }

                    // value
                    xItem = ctx.Element.Element(nameof(KeyValuePair <_, _> .Value));
                    if (xItem == null)
                    {
                        Throw.ArgumentException(Res.XmlSerializationKeyValueMissingValue);
                    }
                    xType = xItem.Attribute(XmlSerializer.AttributeType);
                    Type valueType = xType != null?Reflector.ResolveType(xType.Value) : ctx.Type.GetGenericArguments()[1];

                    if (!TryDeserializeObject(valueType, xItem, null, out object value))
                    {
                        if (xType != null && valueType == null)
                        {
                            Throw.ReflectionException(Res.XmlSerializationCannotResolveType(xType.Value));
                        }
                        Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(valueType));
                    }

                    ctx.Result = Activator.CreateInstance(ctx.Type);
                    Accessors.SetKeyValue(ctx.Result, key, value);
                    return(true);
                }

                return(false);
            }

            void DeserializeBinary(ref TryDeserializeObjectContext ctx)
            {
                if (ctx.Element.IsEmpty)
                {
                    return;
                }
                byte[]     data    = Convert.FromBase64String(ctx.Element.Value);
                XAttribute attrCrc = ctx.Element.Attribute(XmlSerializer.AttributeCrc);

                if (attrCrc != null)
                {
                    if (Crc32.CalculateHash(data).ToString("X8", CultureInfo.InvariantCulture) != attrCrc.Value)
                    {
                        Throw.ArgumentException(Res.XmlSerializationCrcError);
                    }
                }

                ctx.Result = BinarySerializer.Deserialize(data);
            }

            bool TryDeserializeComplexObject(ref TryDeserializeObjectContext ctx)
            {
                if (ctx.Type != null && !ctx.Element.IsEmpty)
                {
                    // 1.) array (both existing and new)
                    if (ctx.Type.IsArray)
                    {
                        ctx.Result = DeserializeArray(ctx.ExistingInstance as Array, ctx.Type.GetElementType(), ctx.Element, true);
                        return(true);
                    }

                    // 2.) existing read-write collection
                    if (ctx.Type.IsReadWriteCollection(ctx.ExistingInstance))
                    {
                        DeserializeContent(ctx.Element, ctx.ExistingInstance);
                        ctx.Result = ctx.ExistingInstance;
                        return(true);
                    }

                    bool isCollection = ctx.Type.IsSupportedCollectionForReflection(out var defaultCtor, out var collectionCtor, out var elementType, out bool isDictionary);

                    // 3.) New collection by collectionCtor (only if there is no defaultCtor)
                    if (isCollection && defaultCtor == null && !ctx.Type.IsValueType)
                    {
                        ctx.Result = DeserializeContentByInitializerCollection(ctx.Element, collectionCtor, elementType, isDictionary);
                        return(true);
                    }

                    ctx.Result = ctx.ExistingInstance ?? (ctx.Type.CanBeCreatedWithoutParameters()
                            ? ctx.Type.IsValueType ? Activator.CreateInstance(ctx.Type) : CreateInstanceAccessor.GetAccessor(ctx.Type).CreateInstance()
                            : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(ctx.Type)));

                    // 4.) New collection by collectionCtor again (there IS defaultCtor but the new instance is read-only so falling back to collectionCtor)
                    if (isCollection && !ctx.Type.IsReadWriteCollection(ctx.Result))
                    {
                        if (collectionCtor != null)
                        {
                            ctx.Result = DeserializeContentByInitializerCollection(ctx.Element, collectionCtor, elementType, isDictionary);
                            return(true);
                        }

                        Throw.SerializationException(Res.XmlSerializationCannotDeserializeReadOnlyCollection(ctx.Type));
                    }

                    // 5.) Newly created collection or any other object (both existing and new)
                    DeserializeContent(ctx.Element, ctx.Result);
                    return(true);
                }

                return(false);
            }

            #endregion

            // null value
            if (element.IsEmpty && (type == null || !type.IsValueType || type.IsNullable()))
            {
                result = null;
                return(true);
            }

            if (type != null && type.IsNullable())
            {
                type = Nullable.GetUnderlyingType(type);
            }

            // a.) If type can be natively parsed, parsing from string
            if (type != null && type.CanBeParsedNatively())
            {
                string value = ReadStringValue(element);
                result = value.Parse(type);
                return(true);
            }

            // b.) Deserialize IXmlSerializable
            string format = element.Attribute(XmlSerializer.AttributeFormat)?.Value;
            if (type != null && format == XmlSerializer.AttributeValueCustom)
            {
                object instance = existingInstance ?? (type.CanBeCreatedWithoutParameters()
                    ? type.IsValueType ? Activator.CreateInstance(type) : CreateInstanceAccessor.GetAccessor(type).CreateInstance()
                    : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(type)));
                if (!(instance is IXmlSerializable xmlSerializable))
                {
                    result = default;
                    Throw.ArgumentException(Res.XmlSerializationNotAnIXmlSerializable(type));
                    return(default);