/// <summary> /// /// </summary> /// <param name="surrogate"></param> /// <param name="obj"></param> /// <param name="firstChild"></param> /// <returns></returns> protected object DeserializeSurrogate(ISerializationSurrogate surrogate, Type objType, int objId, XmlNode firstChild, XmlElement rootElement, object standin) { //NOTE: Technically this isn't necessary because we can be sure it'll //never be called on Components. The GameObject surrogate will handle //deserializing components and any loose references will be skipped //until the deference phase at the end of deserialization. //However, in case serialization wasn't done properly (components were //serialized in-place rather than defered to GameObject serialization), //then we need to ensure we simply skip this in such a case. if (standin == null) { if (objType.IsSubclassOf(typeof(Component))) { return(null); } if (objType.IsSubclassOf(typeof(Component[]))) { return(null); } if (objType == typeof(Component[])) { return(null); } } SerializationInfo info = new SerializationInfo(objType, new DummyConverter()); DeserializeContext context = new DeserializeContext(); context.Deserializer = this; context.ObjId = objId; context.ElementBeingParsed = rootElement; context.ObjectType = objType; context.deserializationObjCache = this.deserializationObjCache; context.deserializationTypeCache = this.deserializationTypeCache; //float through the xml nodes and see what items we need to collect. for (XmlNode node = firstChild; node != null; node = node.NextSibling) { object val = DeserializeCore((XmlElement)node); if (val != null) { info.AddValue(node.Name, val, val.GetType()); } else { info.AddValue(node.Name, null, typeof(object)); } } //if the standin is null, we need to create an instance. //Otherwise, we were given an instance to work with. object obj = standin; if (obj == null) { if (SerializerBase.IsSameOrSubclass(typeof(MulticastDelegate), objType)) { obj = null; } else { obj = CreateInstanceOfType(objType, false); //if(SerializerBase.IsReferenceNull(obj)) // return null; } } //we pass obj in but we also assign it back from the output, just in case //the surrogate decided to do something funky. There is also the simple //possibility that we couldn't create an instance of the object beforehand //so we are actually passing in 'null'. obj = surrogate.SetObjectData(obj, info, new StreamingContext(StreamingContextStates.File, context), this); if (SerializerBase.IsReferenceNull(obj)) { Debug.LogWarning("The surrogate '" + surrogate.ToString() + "' could not create an instance of '" + objType.Name + "' for the element '" + firstChild.ParentNode.Name + "'."); } CacheObject(obj, objId); return(obj); }
/// <summary> /// Main workhorse of the deserilizer. It processes primitives and recursively breaks /// complex types down into smaller primitives to be processed. /// </summary> /// <param name="element"></param> /// <returns></returns> public object DeserializeCore(XmlElement element, object ownerObj = null, object standin = null) { // check if this is a reference to another object int objId; string s = element.GetAttribute("id"); if (int.TryParse(s, out objId)) { object objCached = GetObjFromCache(objId); if (objCached != null) { return(objCached); } } else { //TODO: If this is a defered object then we can't deserialize it just yet anyway objId = -1; } // check for null string value = element.GetAttribute("value"); if (value == "null") { return(null); } int subItems = element.ChildNodes.Count; XmlNode firstChild = element.FirstChild; // load type cache if available if (element.GetAttribute("hasTypeCache") == "true") { LoadTypeCache((XmlElement)firstChild); subItems--; firstChild = firstChild.NextSibling; } // get type Type objType; string typeId = element.GetAttribute("typeid"); if (string.IsNullOrEmpty(typeId)) { // no type id so type information must be present objType = InferTypeFromElement(element); } else { // there is a type id present objType = deserializationTypeCache[Convert.ToInt32(typeId)]; } if (objType == null) { //if there was an id but it's not in the cache yet, this probably means //a circular reference to an object currently being deserialized. We can't //do anything useful with this information right now so we'll have to //add it to the defered deserialization list. if (objId != -1) { //UPDATE: Unused at the moment. Was original intended to proces //Component.gameObject references that had no type info // the component surrogate doesn't add the 'defered' attribute so we need to do that now. element.SetAttribute("defered", "true"); CheckForDeferedDeserialization(ownerObj, element.Name, element); return(null); } //otherwise, something really screwy happened during serialization. Debug.LogWarning("No type info supplied for " + element.Name + ". Assigning null value."); return(null); } // our value object obj = standin; //Before we get crazy with built-in deserailizers we want to look at our //surrogates and see if any of them handle this datatype. ISurrogateSelector temp; var surrogate = this.GetSurrogate(objType, new StreamingContext(StreamingContextStates.File), out temp); if (surrogate != null) { obj = DeserializeSurrogate(surrogate, objType, objId, firstChild, element, standin); CacheObject(obj, objId); if (!SerializerBase.IsReferenceNull(obj)) { return(obj); } } // process enum if (objType.IsEnum) { long val = Convert.ToInt64(value, cult); return(Enum.ToObject(objType, val)); } // process some simple types switch (Type.GetTypeCode(objType)) { case TypeCode.Boolean: return(Convert.ToBoolean(value, cult)); case TypeCode.Byte: return(Convert.ToByte(value, cult)); case TypeCode.Char: return(Convert.ToChar(value, cult)); case TypeCode.DBNull: return(DBNull.Value); case TypeCode.DateTime: return(Convert.ToDateTime(value, cult)); case TypeCode.Decimal: return(Convert.ToDecimal(value, cult)); case TypeCode.Double: return(Convert.ToDouble(value, cult)); case TypeCode.Int16: return(Convert.ToInt16(value, cult)); case TypeCode.Int32: return(Convert.ToInt32(value, cult)); case TypeCode.Int64: return(Convert.ToInt64(value, cult)); case TypeCode.SByte: return(Convert.ToSByte(value, cult)); case TypeCode.Single: return(Convert.ToSingle(value, cult)); case TypeCode.String: return(value); case TypeCode.UInt16: return(Convert.ToUInt16(value, cult)); case TypeCode.UInt32: return(Convert.ToUInt32(value, cult)); case TypeCode.UInt64: return(Convert.ToUInt64(value, cult)); } //deserialize array if (objType.IsArray) { //we need to check the attributes to see if we have a multi-dimensional array string ranks = element.GetAttribute("Ranks"); if (!string.IsNullOrEmpty(ranks)) { return(DeserializeMultiDimensionalArray(objType, objId, subItems, ranks, firstChild)); } return(DeserializeArray(objType, objId, subItems, firstChild)); } //last chance attempt to instantiate the object if (SerializerBase.IsReferenceNull(obj) && standin == null) { obj = CreateInstanceOfType(objType); } //we still have nothing. Just return null. We can't instatiate this object. if (SerializerBase.IsReferenceNull(obj)) { return(null); } //can deserialize self IXmlSerializable xmlSer = obj as IXmlSerializable; if (xmlSer != null) { DeserializeSelf(xmlSer, element); return(obj); } //it's a list object IList lst = obj as IList; if (lst != null) { return(DeserializeIList(lst, firstChild)); } //it's a dictionary object IDictionary dict = obj as IDictionary; if (dict != null) { return(DeserializeIDictionary(dict, firstChild)); } //it's a dictionary entry (key/value pair) if (objType == typeof(DictionaryEntry) || (objType.IsGenericType && objType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>))) { return(DeserializeDictionaryEntry(element, firstChild)); } //it's a regular class or struct DeserializeComplexType(obj, objType, firstChild); CacheObject(obj, objId); return(obj); }