| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.Runtime.Serialization
- {
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- #if !NO_DYNAMIC_CODEGEN
- using System.Reflection.Emit;
- #endif
- using System.Runtime.Serialization.Diagnostics.Application;
- using System.Security;
- using System.Security.Permissions;
- using System.Xml;
- #if USE_REFEMIT
- public delegate object XmlFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces);
- public delegate object XmlFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
- public delegate void XmlFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
- public sealed class XmlFormatReaderGenerator
- #else
- internal delegate object XmlFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces);
- internal delegate object XmlFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
- internal delegate void XmlFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract);
- internal sealed partial class XmlFormatReaderGenerator
- #endif
- {
- [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that was produced within an assert.")]
- [SecurityCritical]
- CriticalHelper helper;
- [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.")]
- [SecurityCritical]
- public XmlFormatReaderGenerator()
- {
- helper = new CriticalHelper();
- }
- [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
- [SecurityCritical]
- public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
- {
- try
- {
- if (TD.DCGenReaderStartIsEnabled())
- {
- TD.DCGenReaderStart("Class", classContract.UnderlyingType.FullName);
- }
- return helper.GenerateClassReader(classContract);
- }
- finally
- {
- if (TD.DCGenReaderStopIsEnabled())
- {
- TD.DCGenReaderStop();
- }
- }
- }
- [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
- [SecurityCritical]
- public XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
- {
- try
- {
- if (TD.DCGenReaderStartIsEnabled())
- {
- TD.DCGenReaderStart("Collection", collectionContract.UnderlyingType.FullName);
- }
- return helper.GenerateCollectionReader(collectionContract);
- }
- finally
- {
- if (TD.DCGenReaderStopIsEnabled())
- {
- TD.DCGenReaderStop();
- }
- }
- }
- [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
- [SecurityCritical]
- public XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
- {
- try
- {
- if (TD.DCGenReaderStartIsEnabled())
- {
- TD.DCGenReaderStart("GetOnlyCollection", collectionContract.UnderlyingType.FullName);
- }
- return helper.GenerateGetOnlyCollectionReader(collectionContract);
- }
- finally
- {
- if (TD.DCGenReaderStopIsEnabled())
- {
- TD.DCGenReaderStop();
- }
- }
- }
- #if !NO_DYNAMIC_CODEGEN
- [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Handles all aspects of IL generation including initializing the DynamicMethod."
- + " Changes to how IL generated could affect how data is deserialized and what gets access to data,"
- + " therefore we mark it for review so that changes to generation logic are reviewed.")]
- partial class CriticalHelper
- {
- CodeGenerator ilg;
- LocalBuilder objectLocal;
- Type objectType;
- ArgBuilder xmlReaderArg;
- ArgBuilder contextArg;
- ArgBuilder memberNamesArg;
- ArgBuilder memberNamespacesArg;
- ArgBuilder collectionContractArg;
- public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
- {
- ilg = new CodeGenerator();
- bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null);
- try
- {
- ilg.BeginMethod("Read" + classContract.StableName.Name + "FromXml", Globals.TypeOfXmlFormatClassReaderDelegate, memberAccessFlag);
- }
- catch (SecurityException securityException)
- {
- if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
- {
- classContract.RequiresMemberAccessForRead(securityException);
- }
- else
- {
- throw;
- }
- }
- InitArgs();
- DemandSerializationFormatterPermission(classContract);
- DemandMemberAccessPermission(memberAccessFlag);
- CreateObject(classContract);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
- InvokeOnDeserializing(classContract);
- LocalBuilder objectId = null;
- if (HasFactoryMethod(classContract))
- {
- objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
- ilg.Stloc(objectId);
- }
- if (classContract.IsISerializable)
- ReadISerializable(classContract);
- else
- ReadClass(classContract);
- bool isFactoryType = InvokeFactoryMethod(classContract, objectId);
- if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType))
- ilg.Call(objectLocal, XmlFormatGeneratorStatics.OnDeserializationMethod, null);
- InvokeOnDeserialized(classContract);
- if (objectId == null || !isFactoryType)
- {
- ilg.Load(objectLocal);
- // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
- // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
- // on DateTimeOffset; which does not work in partial trust.
- if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
- {
- ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfDateTimeOffsetAdapter);
- ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetMethod);
- ilg.ConvertValue(Globals.TypeOfDateTimeOffset, ilg.CurrentMethod.ReturnType);
- }
- else
- {
- ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
- }
- }
- return (XmlFormatClassReaderDelegate)ilg.EndMethod();
- }
- public XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
- {
- ilg = GenerateCollectionReaderHelper(collectionContract, false /*isGetOnlyCollection*/);
- ReadCollection(collectionContract);
- ilg.Load(objectLocal);
- ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType);
- return (XmlFormatCollectionReaderDelegate)ilg.EndMethod();
- }
- public XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
- {
- ilg = GenerateCollectionReaderHelper(collectionContract, true /*isGetOnlyCollection*/);
- ReadGetOnlyCollection(collectionContract);
- return (XmlFormatGetOnlyCollectionReaderDelegate)ilg.EndMethod();
- }
- CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract collectionContract, bool isGetOnlyCollection)
- {
- ilg = new CodeGenerator();
- bool memberAccessFlag = collectionContract.RequiresMemberAccessForRead(null);
- try
- {
- if (isGetOnlyCollection)
- {
- ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + "IsGetOnly", Globals.TypeOfXmlFormatGetOnlyCollectionReaderDelegate, memberAccessFlag);
- }
- else
- {
- ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + string.Empty, Globals.TypeOfXmlFormatCollectionReaderDelegate, memberAccessFlag);
- }
- }
- catch (SecurityException securityException)
- {
- if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
- {
- collectionContract.RequiresMemberAccessForRead(securityException);
- }
- else
- {
- throw;
- }
- }
- InitArgs();
- DemandMemberAccessPermission(memberAccessFlag);
- collectionContractArg = ilg.GetArg(4);
- return ilg;
- }
- void InitArgs()
- {
- xmlReaderArg = ilg.GetArg(0);
- contextArg = ilg.GetArg(1);
- memberNamesArg = ilg.GetArg(2);
- memberNamespacesArg = ilg.GetArg(3);
- }
- void DemandMemberAccessPermission(bool memberAccessFlag)
- {
- if (memberAccessFlag)
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandMemberAccessPermissionMethod);
- }
- }
- void DemandSerializationFormatterPermission(ClassDataContract classContract)
- {
- if (!classContract.HasDataContract && !classContract.IsNonAttributedType)
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandSerializationFormatterPermissionMethod);
- }
- }
- void CreateObject(ClassDataContract classContract)
- {
- Type type = objectType = classContract.UnderlyingType;
- if (type.IsValueType && !classContract.IsNonAttributedType)
- type = Globals.TypeOfValueType;
- objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
- if (classContract.UnderlyingType == Globals.TypeOfDBNull)
- {
- ilg.LoadMember(Globals.TypeOfDBNull.GetField("Value"));
- ilg.Stloc(objectLocal);
- }
- else if (classContract.IsNonAttributedType)
- {
- if (type.IsValueType)
- {
- ilg.Ldloca(objectLocal);
- ilg.InitObj(type);
- }
- else
- {
- ilg.New(classContract.GetNonAttributedTypeConstructor());
- ilg.Stloc(objectLocal);
- }
- }
- else
- {
- ilg.Call(null, XmlFormatGeneratorStatics.GetUninitializedObjectMethod, DataContract.GetIdForInitialization(classContract));
- ilg.ConvertValue(Globals.TypeOfObject, type);
- ilg.Stloc(objectLocal);
- }
- }
- void InvokeOnDeserializing(ClassDataContract classContract)
- {
- if (classContract.BaseContract != null)
- InvokeOnDeserializing(classContract.BaseContract);
- if (classContract.OnDeserializing != null)
- {
- ilg.LoadAddress(objectLocal);
- ilg.ConvertAddress(objectLocal.LocalType, objectType);
- ilg.Load(contextArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
- ilg.Call(classContract.OnDeserializing);
- }
- }
- void InvokeOnDeserialized(ClassDataContract classContract)
- {
- if (classContract.BaseContract != null)
- InvokeOnDeserialized(classContract.BaseContract);
- if (classContract.OnDeserialized != null)
- {
- ilg.LoadAddress(objectLocal);
- ilg.ConvertAddress(objectLocal.LocalType, objectType);
- ilg.Load(contextArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
- ilg.Call(classContract.OnDeserialized);
- }
- }
- bool HasFactoryMethod(ClassDataContract classContract)
- {
- return Globals.TypeOfIObjectReference.IsAssignableFrom(classContract.UnderlyingType);
- }
- bool InvokeFactoryMethod(ClassDataContract classContract, LocalBuilder objectId)
- {
- if (HasFactoryMethod(classContract))
- {
- ilg.Load(contextArg);
- ilg.LoadAddress(objectLocal);
- ilg.ConvertAddress(objectLocal.LocalType, Globals.TypeOfIObjectReference);
- ilg.Load(objectId);
- ilg.Call(XmlFormatGeneratorStatics.GetRealObjectMethod);
- ilg.ConvertValue(Globals.TypeOfObject, ilg.CurrentMethod.ReturnType);
- return true;
- }
- return false;
- }
- void ReadClass(ClassDataContract classContract)
- {
- if (classContract.HasExtensionData)
- {
- LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
- ilg.New(XmlFormatGeneratorStatics.ExtensionDataObjectCtor);
- ilg.Store(extensionDataLocal);
- ReadMembers(classContract, extensionDataLocal);
- ClassDataContract currentContract = classContract;
- while (currentContract != null)
- {
- MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod;
- if (extensionDataSetMethod != null)
- ilg.Call(objectLocal, extensionDataSetMethod, extensionDataLocal);
- currentContract = currentContract.BaseContract;
- }
- }
- else
- ReadMembers(classContract, null /*extensionDataLocal*/);
- }
- void ReadMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal)
- {
- int memberCount = classContract.MemberNames.Length;
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount);
- LocalBuilder memberIndexLocal = ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1);
- int firstRequiredMember;
- bool[] requiredMembers = GetRequiredMembers(classContract, out firstRequiredMember);
- bool hasRequiredMembers = (firstRequiredMember < memberCount);
- LocalBuilder requiredIndexLocal = hasRequiredMembers ? ilg.DeclareLocal(Globals.TypeOfInt, "requiredIndex", firstRequiredMember) : null;
- object forReadElements = ilg.For(null, null, null);
- ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, xmlReaderArg);
- ilg.IfFalseBreak(forReadElements);
- if (hasRequiredMembers)
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetMemberIndexWithRequiredMembersMethod, xmlReaderArg, memberNamesArg, memberNamespacesArg, memberIndexLocal, requiredIndexLocal, extensionDataLocal);
- else
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetMemberIndexMethod, xmlReaderArg, memberNamesArg, memberNamespacesArg, memberIndexLocal, extensionDataLocal);
- if (memberCount > 0)
- {
- Label[] memberLabels = ilg.Switch(memberCount);
- ReadMembers(classContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal);
- ilg.EndSwitch();
- }
- else
- {
- ilg.Pop();
- }
- ilg.EndFor();
- if (hasRequiredMembers)
- {
- ilg.If(requiredIndexLocal, Cmp.LessThan, memberCount);
- ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMissingExceptionMethod, xmlReaderArg, memberIndexLocal, requiredIndexLocal, memberNamesArg);
- ilg.EndIf();
- }
- }
- int ReadMembers(ClassDataContract classContract, bool[] requiredMembers, Label[] memberLabels, LocalBuilder memberIndexLocal, LocalBuilder requiredIndexLocal)
- {
- int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers(classContract.BaseContract, requiredMembers,
- memberLabels, memberIndexLocal, requiredIndexLocal);
- for (int i = 0; i < classContract.Members.Count; i++, memberCount++)
- {
- DataMember dataMember = classContract.Members[i];
- Type memberType = dataMember.MemberType;
- ilg.Case(memberLabels[memberCount], dataMember.Name);
- if (dataMember.IsRequired)
- {
- int nextRequiredIndex = memberCount + 1;
- for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++)
- if (requiredMembers[nextRequiredIndex])
- break;
- ilg.Set(requiredIndexLocal, nextRequiredIndex);
- }
- LocalBuilder value = null;
- if (dataMember.IsGetOnlyCollection)
- {
- ilg.LoadAddress(objectLocal);
- ilg.LoadMember(dataMember.MemberInfo);
- value = ilg.DeclareLocal(memberType, dataMember.Name + "Value");
- ilg.Stloc(value);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value);
- ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace);
- }
- else
- {
- value = ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace);
- ilg.LoadAddress(objectLocal);
- ilg.ConvertAddress(objectLocal.LocalType, objectType);
- ilg.Ldloc(value);
- ilg.StoreMember(dataMember.MemberInfo);
- }
- ilg.Set(memberIndexLocal, memberCount);
- ilg.EndCase();
- }
- return memberCount;
- }
- bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequiredMember)
- {
- int memberCount = contract.MemberNames.Length;
- bool[] requiredMembers = new bool[memberCount];
- GetRequiredMembers(contract, requiredMembers);
- for (firstRequiredMember = 0; firstRequiredMember < memberCount; firstRequiredMember++)
- if (requiredMembers[firstRequiredMember])
- break;
- return requiredMembers;
- }
- int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers)
- {
- int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers(contract.BaseContract, requiredMembers);
- List<DataMember> members = contract.Members;
- for (int i = 0; i < members.Count; i++, memberCount++)
- {
- requiredMembers[memberCount] = members[i].IsRequired;
- }
- return memberCount;
- }
- void ReadISerializable(ClassDataContract classContract)
- {
- ConstructorInfo ctor = classContract.GetISerializableConstructor();
- ilg.LoadAddress(objectLocal);
- ilg.ConvertAddress(objectLocal.LocalType, objectType);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadSerializationInfoMethod, xmlReaderArg, classContract.UnderlyingType);
- ilg.Load(contextArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod);
- ilg.Call(ctor);
- }
- LocalBuilder ReadValue(Type type, string name, string ns)
- {
- LocalBuilder value = ilg.DeclareLocal(type, "valueRead");
- LocalBuilder nullableValue = null;
- int nullables = 0;
- while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
- {
- nullables++;
- type = type.GetGenericArguments()[0];
- }
- PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
- if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
- {
- LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
- ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadAttributesMethod, xmlReaderArg);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadIfNullOrRefMethod, xmlReaderArg, type, DataContract.IsTypeSerializable(type));
- ilg.Stloc(objectId);
- // Deserialize null
- ilg.If(objectId, Cmp.EqualTo, Globals.NullObjectId);
- if (nullables != 0)
- {
- ilg.LoadAddress(value);
- ilg.InitObj(value.LocalType);
- }
- else if (type.IsValueType)
- ThrowValidationException(SR.GetString(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type)));
- else
- {
- ilg.Load(null);
- ilg.Stloc(value);
- }
- // Deserialize value
- // Compare against Globals.NewObjectId, which is set to string.Empty
- ilg.ElseIfIsEmptyString(objectId);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
- ilg.Stloc(objectId);
- if (type.IsValueType)
- {
- ilg.IfNotIsEmptyString(objectId);
- ThrowValidationException(SR.GetString(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
- ilg.EndIf();
- }
- if (nullables != 0)
- {
- nullableValue = value;
- value = ilg.DeclareLocal(type, "innerValueRead");
- }
- if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject)
- {
- ilg.Call(xmlReaderArg, primitiveContract.XmlFormatReaderMethod);
- ilg.Stloc(value);
- if (!type.IsValueType)
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, value);
- }
- else
- {
- InternalDeserialize(value, type, name, ns);
- }
- // Deserialize ref
- ilg.Else();
- if (type.IsValueType)
- ThrowValidationException(SR.GetString(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type)));
- else
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetExistingObjectMethod, objectId, type, name, ns);
- ilg.ConvertValue(Globals.TypeOfObject, type);
- ilg.Stloc(value);
- }
- ilg.EndIf();
- if (nullableValue != null)
- {
- ilg.If(objectId, Cmp.NotEqualTo, Globals.NullObjectId);
- WrapNullableObject(value, nullableValue, nullables);
- ilg.EndIf();
- value = nullableValue;
- }
- }
- else
- {
- InternalDeserialize(value, type, name, ns);
- }
- return value;
- }
- void InternalDeserialize(LocalBuilder value, Type type, string name, string ns)
- {
- ilg.Load(contextArg);
- ilg.Load(xmlReaderArg);
- Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
- ilg.Load(DataContract.GetId(declaredType.TypeHandle));
- ilg.Ldtoken(declaredType);
- ilg.Load(name);
- ilg.Load(ns);
- ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod);
- if (type.IsPointer)
- ilg.Call(XmlFormatGeneratorStatics.UnboxPointer);
- else
- ilg.ConvertValue(Globals.TypeOfObject, type);
- ilg.Stloc(value);
- }
- void WrapNullableObject(LocalBuilder innerValue, LocalBuilder outerValue, int nullables)
- {
- Type innerType = innerValue.LocalType, outerType = outerValue.LocalType;
- ilg.LoadAddress(outerValue);
- ilg.Load(innerValue);
- for (int i = 1; i < nullables; i++)
- {
- Type type = Globals.TypeOfNullable.MakeGenericType(innerType);
- ilg.New(type.GetConstructor(new Type[] { innerType }));
- innerType = type;
- }
- ilg.Call(outerType.GetConstructor(new Type[] { innerType }));
- }
- void ReadCollection(CollectionDataContract collectionContract)
- {
- Type type = collectionContract.UnderlyingType;
- Type itemType = collectionContract.ItemType;
- bool isArray = (collectionContract.Kind == CollectionKind.Array);
- ConstructorInfo constructor = collectionContract.Constructor;
- if (type.IsInterface)
- {
- switch (collectionContract.Kind)
- {
- case CollectionKind.GenericDictionary:
- type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
- constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
- break;
- case CollectionKind.Dictionary:
- type = Globals.TypeOfHashtable;
- constructor = XmlFormatGeneratorStatics.HashtableCtor;
- break;
- case CollectionKind.Collection:
- case CollectionKind.GenericCollection:
- case CollectionKind.Enumerable:
- case CollectionKind.GenericEnumerable:
- case CollectionKind.List:
- case CollectionKind.GenericList:
- type = itemType.MakeArrayType();
- isArray = true;
- break;
- }
- }
- string itemName = collectionContract.ItemName;
- string itemNs = collectionContract.StableName.Namespace;
- objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
- if (!isArray)
- {
- if (type.IsValueType)
- {
- ilg.Ldloca(objectLocal);
- ilg.InitObj(type);
- }
- else
- {
- ilg.New(constructor);
- ilg.Stloc(objectLocal);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
- }
- }
- LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetArraySizeMethod);
- ilg.Stloc(size);
- LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
- ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
- ilg.Stloc(objectId);
- bool canReadPrimitiveArray = false;
- if (isArray && TryReadPrimitiveArray(type, itemType, size))
- {
- canReadPrimitiveArray = true;
- ilg.IfNot();
- }
- ilg.If(size, Cmp.EqualTo, -1);
- LocalBuilder growingCollection = null;
- if (isArray)
- {
- growingCollection = ilg.DeclareLocal(type, "growingCollection");
- ilg.NewArray(itemType, 32);
- ilg.Stloc(growingCollection);
- }
- LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
- object forLoop = ilg.For(i, 0, Int32.MaxValue);
- IsStartElement(memberNamesArg, memberNamespacesArg);
- ilg.If();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
- LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
- if (isArray)
- {
- MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType);
- ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
- ilg.Stloc(growingCollection);
- ilg.StoreArrayElement(growingCollection, i, value);
- }
- else
- StoreCollectionValue(objectLocal, value, collectionContract);
- ilg.Else();
- IsEndElement();
- ilg.If();
- ilg.Break(forLoop);
- ilg.Else();
- HandleUnexpectedItemInCollection(i);
- ilg.EndIf();
- ilg.EndIf();
- ilg.EndFor();
- if (isArray)
- {
- MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
- ilg.Call(null, trimArraySizeMethod, growingCollection, i);
- ilg.Stloc(objectLocal);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
- }
- ilg.Else();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, size);
- if (isArray)
- {
- ilg.NewArray(itemType, size);
- ilg.Stloc(objectLocal);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
- }
- LocalBuilder j = ilg.DeclareLocal(Globals.TypeOfInt, "j");
- ilg.For(j, 0, size);
- IsStartElement(memberNamesArg, memberNamespacesArg);
- ilg.If();
- LocalBuilder itemValue = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
- if (isArray)
- ilg.StoreArrayElement(objectLocal, j, itemValue);
- else
- StoreCollectionValue(objectLocal, itemValue, collectionContract);
- ilg.Else();
- HandleUnexpectedItemInCollection(j);
- ilg.EndIf();
- ilg.EndFor();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, memberNamespacesArg);
- ilg.EndIf();
- if (canReadPrimitiveArray)
- {
- ilg.Else();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal);
- ilg.EndIf();
- }
- }
- void ReadGetOnlyCollection(CollectionDataContract collectionContract)
- {
- Type type = collectionContract.UnderlyingType;
- Type itemType = collectionContract.ItemType;
- bool isArray = (collectionContract.Kind == CollectionKind.Array);
- string itemName = collectionContract.ItemName;
- string itemNs = collectionContract.StableName.Namespace;
- objectLocal = ilg.DeclareLocal(type, "objectDeserialized");
- ilg.Load(contextArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.GetCollectionMemberMethod);
- ilg.ConvertValue(Globals.TypeOfObject, type);
- ilg.Stloc(objectLocal);
- //check that items are actually going to be deserialized into the collection
- IsStartElement(memberNamesArg, memberNamespacesArg);
- ilg.If();
- ilg.If(objectLocal, Cmp.EqualTo, null);
- ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type);
- ilg.Else();
- LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
- if (isArray)
- {
- ilg.Load(objectLocal);
- ilg.Call(XmlFormatGeneratorStatics.GetArrayLengthMethod);
- ilg.Stloc(size);
- }
- ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal);
- LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
- object forLoop = ilg.For(i, 0, Int32.MaxValue);
- IsStartElement(memberNamesArg, memberNamespacesArg);
- ilg.If();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
- LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
- if (isArray)
- {
- ilg.If(size, Cmp.EqualTo, i);
- ilg.Call(null, XmlFormatGeneratorStatics.ThrowArrayExceededSizeExceptionMethod, size, type);
- ilg.Else();
- ilg.StoreArrayElement(objectLocal, i, value);
- ilg.EndIf();
- }
- else
- StoreCollectionValue(objectLocal, value, collectionContract);
- ilg.Else();
- IsEndElement();
- ilg.If();
- ilg.Break(forLoop);
- ilg.Else();
- HandleUnexpectedItemInCollection(i);
- ilg.EndIf();
- ilg.EndIf();
- ilg.EndFor();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, memberNamespacesArg);
- ilg.EndIf();
- ilg.EndIf();
- }
- bool TryReadPrimitiveArray(Type type, Type itemType, LocalBuilder size)
- {
- PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
- if (primitiveContract == null)
- return false;
- string readArrayMethod = null;
- switch (Type.GetTypeCode(itemType))
- {
- case TypeCode.Boolean:
- readArrayMethod = "TryReadBooleanArray";
- break;
- case TypeCode.DateTime:
- readArrayMethod = "TryReadDateTimeArray";
- break;
- case TypeCode.Decimal:
- readArrayMethod = "TryReadDecimalArray";
- break;
- case TypeCode.Int32:
- readArrayMethod = "TryReadInt32Array";
- break;
- case TypeCode.Int64:
- readArrayMethod = "TryReadInt64Array";
- break;
- case TypeCode.Single:
- readArrayMethod = "TryReadSingleArray";
- break;
- case TypeCode.Double:
- readArrayMethod = "TryReadDoubleArray";
- break;
- default:
- break;
- }
- if (readArrayMethod != null)
- {
- ilg.Load(xmlReaderArg);
- ilg.Load(contextArg);
- ilg.Load(memberNamesArg);
- ilg.Load(memberNamespacesArg);
- ilg.Load(size);
- ilg.Ldloca(objectLocal);
- ilg.Call(typeof(XmlReaderDelegator).GetMethod(readArrayMethod, Globals.ScanAllMembers));
- return true;
- }
- return false;
- }
- LocalBuilder ReadCollectionItem(CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
- {
- if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary)
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.ResetAttributesMethod);
- LocalBuilder value = ilg.DeclareLocal(itemType, "valueRead");
- ilg.Load(collectionContractArg);
- ilg.Call(XmlFormatGeneratorStatics.GetItemContractMethod);
- ilg.Load(xmlReaderArg);
- ilg.Load(contextArg);
- ilg.Call(XmlFormatGeneratorStatics.ReadXmlValueMethod);
- ilg.ConvertValue(Globals.TypeOfObject, itemType);
- ilg.Stloc(value);
- return value;
- }
- else
- {
- return ReadValue(itemType, itemName, itemNs);
- }
- }
- void StoreCollectionValue(LocalBuilder collection, LocalBuilder value, CollectionDataContract collectionContract)
- {
- if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary)
- {
- ClassDataContract keyValuePairContract = DataContract.GetDataContract(value.LocalType) as ClassDataContract;
- if (keyValuePairContract == null)
- {
- Fx.Assert("Failed to create contract for KeyValuePair type");
- }
- DataMember keyMember = keyValuePairContract.Members[0];
- DataMember valueMember = keyValuePairContract.Members[1];
- LocalBuilder pairKey = ilg.DeclareLocal(keyMember.MemberType, keyMember.Name);
- LocalBuilder pairValue = ilg.DeclareLocal(valueMember.MemberType, valueMember.Name);
- ilg.LoadAddress(value);
- ilg.LoadMember(keyMember.MemberInfo);
- ilg.Stloc(pairKey);
- ilg.LoadAddress(value);
- ilg.LoadMember(valueMember.MemberInfo);
- ilg.Stloc(pairValue);
- ilg.Call(collection, collectionContract.AddMethod, pairKey, pairValue);
- if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
- ilg.Pop();
- }
- else
- {
- ilg.Call(collection, collectionContract.AddMethod, value);
- if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid)
- ilg.Pop();
- }
- }
- void HandleUnexpectedItemInCollection(LocalBuilder iterator)
- {
- IsStartElement();
- ilg.If();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.SkipUnknownElementMethod, xmlReaderArg);
- ilg.Dec(iterator);
- ilg.Else();
- ThrowUnexpectedStateException(XmlNodeType.Element);
- ilg.EndIf();
- }
- void IsStartElement(ArgBuilder nameArg, ArgBuilder nsArg)
- {
- ilg.Call(xmlReaderArg, XmlFormatGeneratorStatics.IsStartElementMethod2, nameArg, nsArg);
- }
- void IsStartElement()
- {
- ilg.Call(xmlReaderArg, XmlFormatGeneratorStatics.IsStartElementMethod0);
- }
- void IsEndElement()
- {
- ilg.Load(xmlReaderArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.NodeTypeProperty);
- ilg.Load(XmlNodeType.EndElement);
- ilg.Ceq();
- }
- void ThrowUnexpectedStateException(XmlNodeType expectedState)
- {
- ilg.Call(null, XmlFormatGeneratorStatics.CreateUnexpectedStateExceptionMethod, expectedState, xmlReaderArg);
- ilg.Throw();
- }
- void ThrowValidationException(string msg, params object[] values)
- {
- if (values != null && values.Length > 0)
- ilg.CallStringFormat(msg, values);
- else
- ilg.Load(msg);
- ThrowValidationException();
- }
- void ThrowValidationException()
- {
- ilg.New(XmlFormatGeneratorStatics.SerializationExceptionCtor);
- ilg.Throw();
- }
- }
- #endif
- [Fx.Tag.SecurityNote(Critical = "Elevates by calling GetUninitializedObject which has a LinkDemand.",
- Safe = "Marked as such so that it's callable from transparent generated IL. Takes id as parameter which "
- + " is guaranteed to be in internal serialization cache.")]
- [SecuritySafeCritical]
- #if USE_REFEMIT
- public static object UnsafeGetUninitializedObject(int id)
- #else
- static internal object UnsafeGetUninitializedObject(int id)
- #endif
- {
- return FormatterServices.GetUninitializedObject(DataContract.GetDataContractForInitialization(id).TypeForInitialization);
- }
- }
- }
|