Exemplo n.º 1
0
        public ICollection <BlobObject> StreamObjects <TDoc, TCursor>(IO.TagElementStream <TDoc, TCursor, string> s,
                                                                      ICollection <BlobObject> results, Engine.BlamEngineTargetHandle gameTarget)
            where TDoc : class
            where TCursor : class
        {
            Contract.Requires <ArgumentNullException>(!gameTarget.IsNone);

            if (s.IsReading)
            {
                results = new List <BlobObject>();
            }

            var ctxt = new SerializeObjectContext(this, gameTarget);

            s.StreamElements("BlobObject", results, ctxt, SerializeObject,
                             _ctxt => null);

            return(results);
        }
Exemplo n.º 2
0
        static void SerializeObject <TDoc, TCursor>(IO.TagElementStream <TDoc, TCursor, string> s, SerializeObjectContext ctxt,
                                                    ref BlobObject obj)
            where TDoc : class
            where TCursor : class
        {
            Contract.Requires(obj != null || s.IsReading);

            const string kAttributeNameSignature = "signature";
            const string kAttributeNameVersion   = "version";

            if (s.IsReading)
            {
                string group_tag = null;
                s.ReadAttribute(kAttributeNameSignature, ref group_tag);

                int version = TypeExtensions.kNone;
                s.ReadAttribute(kAttributeNameVersion, ref version);

                BlobGroup blob_group;
                BlobGroupVersionAndBuildInfo info_for_version;
                if (ctxt.System.TryGetBlobGroup(group_tag, version, out blob_group, out info_for_version))
                {
                    var target_build = ctxt.GameTarget.Build;

                    if (!info_for_version.BuildHandle.IsWithinSameBranch(target_build))
                    {
                        s.ThrowReadException(SerializeObjectFoundBuildIncompatibility(ctxt.System,
                                                                                      blob_group, version, info_for_version.BuildHandle, target_build));
                    }

                    obj = ctxt.System.CreateObject(Blam.Engine.BlamEngineTargetHandle.None, blob_group, version);
                }
                else
                {
                    string msg = string.Format("{0}: No blob matching '{1}'/v{2} exists",
                                               ctxt.GameTarget.ToDisplayString(), group_tag, version);
                    s.ThrowReadException(new System.IO.InvalidDataException(msg));
                }
            }
            else if (s.IsWriting)
            {
                s.WriteAttribute(kAttributeNameSignature, obj.SystemGroup.GroupTag.TagString);
                s.WriteAttribute(kAttributeNameVersion, obj.Version);
            }
            s.StreamAttribute("flags", obj, _obj => _obj.BlobFlags);

            obj.Serialize(s);
        }
Exemplo n.º 3
0
        private void SerializeObject(object obj, bool typeNeeded, XmlWriter writer, DesignerSerializationVisibility visibility)
        {
            #region Local Methods to reduce complexity

            bool TrySerializeKeyValue(ref SerializeObjectContext ctx)
            {
                // 1.) KeyValue 1: DictionaryEntry: can be serialized recursively. Just handling to avoid binary serialization.
                if (ctx.Type == Reflector.DictionaryEntryType)
                {
                    if (ctx.TypeNeeded)
                    {
                        ctx.Writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(ctx.Type));
                    }

                    SerializeMembers(ctx.Object, ctx.Writer, ctx.Visibility);
                    return(true);
                }

                // 2.) KeyValue 2: KeyValuePair: properties are read-only so special support needed
                if (ctx.Type.IsGenericTypeOf(Reflector.KeyValuePairType))
                {
                    if (ctx.TypeNeeded)
                    {
                        ctx.Writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(ctx.Type));
                    }

                    object key   = Accessors.GetPropertyValue(ctx.Object, nameof(KeyValuePair <_, _> .Key));
                    object value = Accessors.GetPropertyValue(ctx.Object, nameof(KeyValuePair <_, _> .Value));

                    ctx.Writer.WriteStartElement(nameof(KeyValuePair <_, _> .Key));
                    if (key == null)
                    {
                        ctx.Writer.WriteEndElement();
                    }
                    else
                    {
                        SerializeObject(key, key.GetType() != ctx.Type.GetGenericArguments()[0], ctx.Writer, ctx.Visibility);
                        ctx.Writer.WriteFullEndElement();
                    }

                    ctx.Writer.WriteStartElement(nameof(KeyValuePair <_, _> .Value));
                    if (value == null)
                    {
                        ctx.Writer.WriteEndElement();
                    }
                    else
                    {
                        SerializeObject(value, value.GetType() != ctx.Type.GetGenericArguments()[1], ctx.Writer, ctx.Visibility);
                        ctx.Writer.WriteFullEndElement();
                    }

                    return(true);
                }

                return(false);
            }

            bool TrySerializeComplexObject(ref SerializeObjectContext ctx)
            {
                // 1.) collection: if can be trusted in all circumstances
                if (ctx.Object is IEnumerable enumerable)
                {
                    Type elementType = null;

                    // if can be trusted in all circumstances
                    if (IsTrustedCollection(ctx.Type)
                        // or recursive is requested
                        || ((ctx.Visibility == DesignerSerializationVisibility.Content || RecursiveSerializationAsFallback)
                            // and is a supported collection or serialization is forced
                            && (ForceReadonlyMembersAndCollections || ctx.Type.IsSupportedCollectionForReflection(out var _, out var _, out elementType, out var _))))
                    {
                        SerializeCollection(enumerable, elementType ?? ctx.Type.GetCollectionElementType(), ctx.TypeNeeded, ctx.Writer, ctx.Visibility);
                        return(true);
                    }

                    if (ctx.Visibility == DesignerSerializationVisibility.Content || RecursiveSerializationAsFallback)
                    {
                        Throw.SerializationException(Res.XmlSerializationCannotSerializeUnsupportedCollection(ctx.Type, Options));
                    }
                    Throw.SerializationException(Res.XmlSerializationCannotSerializeCollection(ctx.Type, Options));
                }

                // 2.) recursive serialization of any object, if requested
                if (RecursiveSerializationAsFallback || ctx.Visibility == DesignerSerializationVisibility.Content
                    // or when it has public properties/fields only
                    || IsTrustedType(ctx.Type))
                {
                    if (ctx.TypeNeeded)
                    {
                        ctx.Writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(ctx.Type));
                    }

                    SerializeMembers(ctx.Object, ctx.Writer, ctx.Visibility);
                    return(true);
                }

                return(false);
            }

            #endregion

            if (obj == null)
            {
                return;
            }

            Type type = obj.GetType();

            // a.) If type can be natively parsed, simple writing
            if (type.CanBeParsedNatively())
            {
                if (typeNeeded)
                {
                    writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(type));
                }

                WriteStringValue(obj, writer);
                return;
            }

            // b.) IXmlSerializable
            if (obj is IXmlSerializable xmlSerializable && ProcessXmlSerializable)
            {
                if (typeNeeded)
                {
                    writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(type));
                }

                SerializeXmlSerializable(xmlSerializable, writer);
                return;
            }

            // c.) Using type converter of the type if applicable
            TypeConverter converter = TypeDescriptor.GetConverter(type);
            if (converter.CanConvertTo(Reflector.StringType) && converter.CanConvertFrom(Reflector.StringType))
            {
                if (typeNeeded)
                {
                    writer.WriteAttributeString(XmlSerializer.AttributeType, GetTypeString(type));
                }

                // ReSharper disable once AssignNullToNotNullAttribute
                writer.WriteString(converter.ConvertToInvariantString(obj));
                return;
            }

            var context = new SerializeObjectContext {
                Object = obj, Type = type, TypeNeeded = typeNeeded, Writer = writer, Visibility = visibility
            };

            // d.) Key/Value
            if (TrySerializeKeyValue(ref context))
            {
                return;
            }

            // e.) value type as binary only if enabled
            if (type.IsValueType && CompactSerializationOfStructures && BinarySerializer.TrySerializeValueType((ValueType)obj, out byte[] data))