|
//------------------------------------------------------------------------------
// <copyright file="XmlSerializationReaderILGen.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Serialization {
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Security;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
internal class XmlSerializationReaderILGen : XmlSerializationILGen {
Hashtable idNames = new Hashtable();
// Mapping name->id_XXXNN field
Dictionary<string, FieldBuilder> idNameFields = new Dictionary<string, FieldBuilder>();
Hashtable enums;
int nextIdNumber = 0;
int nextWhileLoopIndex = 0;
internal Hashtable Enums {
get {
if (enums == null) {
enums = new Hashtable();
}
return enums;
}
}
class CreateCollectionInfo {
string name;
TypeDesc td;
internal CreateCollectionInfo(string name, TypeDesc td) {
this.name = name;
this.td = td;
}
internal string Name {
get { return name; }
}
internal TypeDesc TypeDesc {
get { return td; }
}
}
class Member {
string source;
string arrayName;
string arraySource;
string choiceArrayName;
string choiceSource;
string choiceArraySource;
MemberMapping mapping;
bool isArray;
bool isList;
bool isNullable;
bool multiRef;
int fixupIndex = -1;
string paramsReadSource;
string checkSpecifiedSource;
internal Member(XmlSerializationReaderILGen outerClass, string source, string arrayName, int i, MemberMapping mapping)
: this(outerClass, source, null, arrayName, i, mapping, false, null) {
}
internal Member(XmlSerializationReaderILGen outerClass, string source, string arrayName, int i, MemberMapping mapping, string choiceSource)
: this(outerClass, source, null, arrayName, i, mapping, false, choiceSource) {
}
internal Member(XmlSerializationReaderILGen outerClass, string source, string arraySource, string arrayName, int i, MemberMapping mapping)
: this(outerClass, source, arraySource, arrayName, i, mapping, false, null) {
}
internal Member(XmlSerializationReaderILGen outerClass, string source, string arraySource, string arrayName, int i, MemberMapping mapping, string choiceSource)
: this(outerClass, source, arraySource, arrayName, i, mapping, false, choiceSource) {
}
internal Member(XmlSerializationReaderILGen outerClass, string source, string arrayName, int i, MemberMapping mapping, bool multiRef)
: this(outerClass, source, null, arrayName, i, mapping, multiRef, null) {
}
internal Member(XmlSerializationReaderILGen outerClass, string source, string arraySource, string arrayName, int i, MemberMapping mapping, bool multiRef, string choiceSource) {
this.source = source;
this.arrayName = arrayName + "_" + i.ToString(CultureInfo.InvariantCulture);
this.choiceArrayName = "choice_" + this.arrayName;
this.choiceSource = choiceSource;
if (mapping.TypeDesc.IsArrayLike) {
if (arraySource != null)
this.arraySource = arraySource;
else
this.arraySource = outerClass.GetArraySource(mapping.TypeDesc, this.arrayName, multiRef);
isArray = mapping.TypeDesc.IsArray;
isList = !isArray;
if (mapping.ChoiceIdentifier != null) {
this.choiceArraySource = outerClass.GetArraySource(mapping.TypeDesc, this.choiceArrayName, multiRef);
string a = choiceArrayName;
string c = "c" + a;
string choiceTypeFullName = mapping.ChoiceIdentifier.Mapping.TypeDesc.CSharpName;
string castString = "(" + choiceTypeFullName + "[])";
string init = a + " = " + castString +
"EnsureArrayIndex(" + a + ", " + c + ", " + outerClass.RaCodeGen.GetStringForTypeof(choiceTypeFullName) + ");";
this.choiceArraySource = init + outerClass.RaCodeGen.GetStringForArrayMember(a, c + "++", mapping.ChoiceIdentifier.Mapping.TypeDesc);
}
else {
this.choiceArraySource = this.choiceSource;
}
}
else {
this.arraySource = arraySource == null ? source : arraySource;
this.choiceArraySource = this.choiceSource;
}
this.mapping = mapping;
}
internal MemberMapping Mapping {
get { return mapping; }
}
internal string Source {
get { return source; }
}
internal string ArrayName {
get { return arrayName; }
}
internal string ArraySource {
get { return arraySource; }
}
internal bool IsList {
get { return isList; }
}
internal bool IsArrayLike {
get { return (isArray || isList); }
}
internal bool IsNullable {
get { return isNullable; }
set { isNullable = value; }
}
internal bool MultiRef {
get { return multiRef; }
set { multiRef = value; }
}
internal int FixupIndex {
get { return fixupIndex; }
set { fixupIndex = value; }
}
internal string ParamsReadSource {
get { return paramsReadSource; }
set { paramsReadSource = value; }
}
internal string CheckSpecifiedSource {
get { return checkSpecifiedSource; }
set { checkSpecifiedSource = value; }
}
internal string ChoiceSource {
get { return choiceSource; }
}
internal string ChoiceArrayName {
get { return choiceArrayName; }
}
internal string ChoiceArraySource {
get { return choiceArraySource; }
}
}
internal XmlSerializationReaderILGen(TypeScope[] scopes, string access, string className)
: base(scopes, access, className) {
}
internal void GenerateBegin() {
this.typeBuilder = CodeGenerator.CreateTypeBuilder(
ModuleBuilder,
ClassName,
TypeAttributes | TypeAttributes.BeforeFieldInit,
typeof(XmlSerializationReader),
CodeGenerator.EmptyTypeArray);
foreach (TypeScope scope in Scopes) {
foreach (TypeMapping mapping in scope.TypeMappings) {
if (mapping is StructMapping || mapping is EnumMapping || mapping is NullableMapping)
MethodNames.Add(mapping, NextMethodName(mapping.TypeDesc.Name));
}
RaCodeGen.WriteReflectionInit(scope);
}
}
internal override void GenerateMethod(TypeMapping mapping) {
if (GeneratedMethods.Contains(mapping))
return;
GeneratedMethods[mapping] = mapping;
if (mapping is StructMapping) {
WriteStructMethod((StructMapping)mapping);
}
else if (mapping is EnumMapping) {
WriteEnumMethod((EnumMapping)mapping);
}
else if (mapping is NullableMapping) {
WriteNullableMethod((NullableMapping)mapping);
}
}
internal void GenerateEnd(string[] methods, XmlMapping[] xmlMappings, Type[] types) {
GenerateReferencedMethods();
GenerateInitCallbacksMethod();
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(typeof(void), "InitIDs", CodeGenerator.EmptyTypeArray, CodeGenerator.EmptyStringArray,
CodeGenerator.ProtectedOverrideMethodAttributes);
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_NameTable = typeof(XmlReader).GetMethod(
"get_NameTable",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlNameTable_Add = typeof(XmlNameTable).GetMethod(
"Add",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
foreach (string id in idNames.Keys) {
//
ilg.Ldarg(0);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NameTable);
ilg.Ldstr(id);
ilg.Call(XmlNameTable_Add);
Debug.Assert(idNameFields.ContainsKey(id));
ilg.StoreMember(idNameFields[id]);
}
ilg.EndMethod();
this.typeBuilder.DefineDefaultConstructor(
CodeGenerator.PublicMethodAttributes);
Type readerType = this.typeBuilder.CreateType();
CreatedTypes.Add(readerType.Name, readerType);
}
internal string GenerateElement(XmlMapping xmlMapping) {
if (!xmlMapping.IsReadable)
return null;
if (!xmlMapping.GenerateSerializer)
throw new ArgumentException(Res.GetString(Res.XmlInternalError), "xmlMapping");
if (xmlMapping is XmlTypeMapping)
return GenerateTypeElement((XmlTypeMapping)xmlMapping);
else if (xmlMapping is XmlMembersMapping)
return GenerateMembersElement((XmlMembersMapping)xmlMapping);
else
throw new ArgumentException(Res.GetString(Res.XmlInternalError), "xmlMapping");
}
void WriteIsStartTag(string name, string ns) {
WriteID(name);
WriteID(ns);
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_IsStartElement = typeof(XmlReader).GetMethod(
"IsStartElement",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Ldarg(0);
ilg.LoadMember(idNameFields[name ?? String.Empty]);
ilg.Ldarg(0);
ilg.LoadMember(idNameFields[ns ?? String.Empty]);
ilg.Call(XmlReader_IsStartElement);
ilg.If();
}
void WriteUnknownNode(string func, string node, ElementAccessor e, bool anyIfs) {
if (anyIfs) {
ilg.Else();
}
List<Type> argTypes = new List<Type>();
ilg.Ldarg(0);
Debug.Assert(node == "null" || node == "(object)p");
if (node == "null")
ilg.Load(null);
else {
object pVar = ilg.GetVariable("p");
ilg.Load(pVar);
ilg.ConvertValue(ilg.GetVariableType(pVar), typeof(object));
}
argTypes.Add(typeof(object));
if (e != null) {
string expectedElement = e.Form == XmlSchemaForm.Qualified ? e.Namespace : "";
expectedElement += ":";
expectedElement += e.Name;
ilg.Ldstr(ReflectionAwareILGen.GetCSharpString(expectedElement));
argTypes.Add(typeof(string));
}
MethodInfo method = typeof(XmlSerializationReader).GetMethod(
func,
CodeGenerator.InstanceBindingFlags,
null,
argTypes.ToArray(),
null
);
ilg.Call(method);
if (anyIfs) {
ilg.EndIf();
}
}
void GenerateInitCallbacksMethod() {
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(typeof(void), "InitCallbacks", CodeGenerator.EmptyTypeArray, CodeGenerator.EmptyStringArray,
CodeGenerator.ProtectedOverrideMethodAttributes);
string dummyArrayMethodName = NextMethodName("Array");
bool needDummyArrayMethod = false;
ilg.EndMethod();
if (needDummyArrayMethod) {
ilg.BeginMethod(
typeof(object),
GetMethodBuilder(dummyArrayMethodName),
CodeGenerator.EmptyTypeArray,
CodeGenerator.EmptyStringArray,
CodeGenerator.PrivateMethodAttributes);
MethodInfo XmlSerializationReader_UnknownNode1 = typeof(XmlSerializationReader).GetMethod(
"UnknownNode",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(object) },
null
);
ilg.Ldarg(0);
ilg.Load(null);
ilg.Call(XmlSerializationReader_UnknownNode1);
ilg.Load(null);
ilg.EndMethod();
}
}
string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) {
return GenerateLiteralMembersElement(xmlMembersMapping);
}
string GetChoiceIdentifierSource(MemberMapping[] mappings, MemberMapping member) {
string choiceSource = null;
if (member.ChoiceIdentifier != null) {
for (int j = 0; j < mappings.Length; j++) {
if (mappings[j].Name == member.ChoiceIdentifier.MemberName) {
choiceSource = "p[" + j.ToString(CultureInfo.InvariantCulture) + "]";
break;
}
}
#if DEBUG
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
if (choiceSource == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Can not find " + member.ChoiceIdentifier.MemberName + " in the members mapping."));
#endif
}
return choiceSource;
}
string GetChoiceIdentifierSource(MemberMapping mapping, string parent, TypeDesc parentTypeDesc) {
if (mapping.ChoiceIdentifier == null) return "";
CodeIdentifier.CheckValidIdentifier(mapping.ChoiceIdentifier.MemberName);
return RaCodeGen.GetStringForMember(parent, mapping.ChoiceIdentifier.MemberName, parentTypeDesc);
}
string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping) {
ElementAccessor element = xmlMembersMapping.Accessor;
MemberMapping[] mappings = ((MembersMapping)element.Mapping).Members;
bool hasWrapperElement = ((MembersMapping)element.Mapping).HasWrapperElement;
string methodName = NextMethodName(element.Name);
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(
typeof(object[]),
methodName,
CodeGenerator.EmptyTypeArray,
CodeGenerator.EmptyStringArray,
CodeGenerator.PublicMethodAttributes
);
ilg.Load(null);
ilg.Stloc(ilg.ReturnLocal);
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod(
"MoveToContent",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
LocalBuilder localP = ilg.DeclareLocal(typeof(object[]), "p");
ilg.NewArray(typeof(object), mappings.Length);
ilg.Stloc(localP);
InitializeValueTypes("p", mappings);
int wrapperLoopIndex = 0;
if (hasWrapperElement) {
wrapperLoopIndex = WriteWhileNotLoopStart();
WriteIsStartTag(element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : "");
}
Member anyText = null;
Member anyElement = null;
Member anyAttribute = null;
ArrayList membersList = new ArrayList();
ArrayList textOrArrayMembersList = new ArrayList();
ArrayList attributeMembersList = new ArrayList();
for (int i = 0; i < mappings.Length; i++) {
MemberMapping mapping = mappings[i];
string source = "p[" + i.ToString(CultureInfo.InvariantCulture) + "]";
string arraySource = source;
if (mapping.Xmlns != null) {
arraySource = "((" + mapping.TypeDesc.CSharpName + ")" + source + ")";
}
string choiceSource = GetChoiceIdentifierSource(mappings, mapping);
Member member = new Member(this, source, arraySource, "a", i, mapping, choiceSource);
Member anyMember = new Member(this, source, null, "a", i, mapping, choiceSource);
if (!mapping.IsSequence)
member.ParamsReadSource = "paramsRead[" + i.ToString(CultureInfo.InvariantCulture) + "]";
if (mapping.CheckSpecified == SpecifiedAccessor.ReadWrite) {
string nameSpecified = mapping.Name + "Specified";
for (int j = 0; j < mappings.Length; j++) {
if (mappings[j].Name == nameSpecified) {
member.CheckSpecifiedSource = "p[" + j.ToString(CultureInfo.InvariantCulture) + "]";
break;
}
}
}
bool foundAnyElement = false;
if (mapping.Text != null) anyText = anyMember;
if (mapping.Attribute != null && mapping.Attribute.Any)
anyAttribute = anyMember;
if (mapping.Attribute != null || mapping.Xmlns != null)
attributeMembersList.Add(member);
else if (mapping.Text != null)
textOrArrayMembersList.Add(member);
if (!mapping.IsSequence) {
for (int j = 0; j < mapping.Elements.Length; j++) {
if (mapping.Elements[j].Any && mapping.Elements[j].Name.Length == 0) {
anyElement = anyMember;
if (mapping.Attribute == null && mapping.Text == null)
textOrArrayMembersList.Add(anyMember);
foundAnyElement = true;
break;
}
}
}
if (mapping.Attribute != null || mapping.Text != null || foundAnyElement)
membersList.Add(anyMember);
else if (mapping.TypeDesc.IsArrayLike && !(mapping.Elements.Length == 1 && mapping.Elements[0].Mapping is ArrayMapping)) {
membersList.Add(anyMember);
textOrArrayMembersList.Add(anyMember);
}
else {
if (mapping.TypeDesc.IsArrayLike && !mapping.TypeDesc.IsArray)
member.ParamsReadSource = null; // collection
membersList.Add(member);
}
}
Member[] members = (Member[])membersList.ToArray(typeof(Member));
Member[] textOrArrayMembers = (Member[])textOrArrayMembersList.ToArray(typeof(Member));
if (members.Length > 0 && members[0].Mapping.IsReturnValue) {
MethodInfo XmlSerializationReader_set_IsReturnValue = typeof(XmlSerializationReader).GetMethod(
"set_IsReturnValue",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Boolean) },
null
);
ilg.Ldarg(0);
ilg.Ldc(true);
ilg.Call(XmlSerializationReader_set_IsReturnValue);
}
WriteParamsRead(mappings.Length);
if (attributeMembersList.Count > 0) {
Member[] attributeMembers = (Member[])attributeMembersList.ToArray(typeof(Member));
WriteMemberBegin(attributeMembers);
WriteAttributes(attributeMembers, anyAttribute, "UnknownNode", localP);
WriteMemberEnd(attributeMembers);
MethodInfo XmlReader_MoveToElement = typeof(XmlReader).GetMethod(
"MoveToElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToElement);
ilg.Pop();
}
WriteMemberBegin(textOrArrayMembers);
if (hasWrapperElement) {
MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod(
"get_IsEmptyElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_IsEmptyElement);
ilg.If();
{
MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
"Skip",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_Skip);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
ilg.WhileContinue();
}
ilg.EndIf();
MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod(
"ReadStartElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadStartElement);
}
if (IsSequence(members)) {
ilg.Ldc(0);
ilg.Stloc(typeof(Int32), "state");
}
int loopIndex = WriteWhileNotLoopStart();
string unknownNode = "UnknownNode((object)p, " + ExpectedElements(members) + ");";
WriteMemberElements(members, unknownNode, unknownNode, anyElement, anyText);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
WriteWhileLoopEnd(loopIndex);
WriteMemberEnd(textOrArrayMembers);
if (hasWrapperElement) {
MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod(
"ReadEndElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadEndElement);
WriteUnknownNode("UnknownNode", "null", element, true);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
WriteWhileLoopEnd(wrapperLoopIndex);
}
ilg.Ldloc(ilg.GetLocal("p"));
ilg.EndMethod();
return methodName;
}
void InitializeValueTypes(string arrayName, MemberMapping[] mappings) {
for (int i = 0; i < mappings.Length; i++) {
if (!mappings[i].TypeDesc.IsValueType)
continue;
LocalBuilder arrayLoc = ilg.GetLocal(arrayName);
ilg.Ldloc(arrayLoc);
ilg.Ldc(i);
RaCodeGen.ILGenForCreateInstance(ilg, mappings[i].TypeDesc.Type, false, false);
ilg.ConvertValue(mappings[i].TypeDesc.Type, typeof(object));
ilg.Stelem(arrayLoc.LocalType.GetElementType());
}
}
string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) {
ElementAccessor element = xmlTypeMapping.Accessor;
TypeMapping mapping = element.Mapping;
string methodName = NextMethodName(element.Name);
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(
typeof(object),
methodName,
CodeGenerator.EmptyTypeArray,
CodeGenerator.EmptyStringArray,
CodeGenerator.PublicMethodAttributes
);
LocalBuilder oLoc = ilg.DeclareLocal(typeof(object), "o");
ilg.Load(null);
ilg.Stloc(oLoc);
MemberMapping member = new MemberMapping();
member.TypeDesc = mapping.TypeDesc;
//member.ReadOnly = !mapping.TypeDesc.HasDefaultConstructor;
member.Elements = new ElementAccessor[] { element };
Member[] members = new Member[] { new Member(this, "o", "o", "a", 0, member) };
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod(
"MoveToContent",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
string unknownNode = "UnknownNode(null, " + ExpectedElements(members) + ");";
WriteMemberElements(members, "throw CreateUnknownNodeException();", unknownNode, element.Any ? members[0] : null, null);
ilg.Ldloc(oLoc);
// for code compat as compiler does
ilg.Stloc(ilg.ReturnLocal);
ilg.Ldloc(ilg.ReturnLocal);
ilg.EndMethod();
return methodName;
}
string NextMethodName(string name) {
return "Read" + (++NextMethodNumber).ToString(CultureInfo.InvariantCulture) + "_" + CodeIdentifier.MakeValidInternal(name);
}
string NextIdName(string name) {
return "id" + (++nextIdNumber).ToString(CultureInfo.InvariantCulture) + "_" + CodeIdentifier.MakeValidInternal(name);
}
void WritePrimitive(TypeMapping mapping, string source) {
System.Diagnostics.Debug.Assert(source == "Reader.ReadElementString()" || source == "Reader.ReadString()"
|| source == "false" || source == "Reader.Value" || source == "vals[i]");
if (mapping is EnumMapping) {
string enumMethodName = ReferenceMapping(mapping);
if (enumMethodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlMissingMethodEnum, mapping.TypeDesc.Name));
// For enum, its read method (eg. Read1_Gender) could be called multiple times
// prior to its declaration.
MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
enumMethodName,
CodeGenerator.PrivateMethodAttributes,
mapping.TypeDesc.Type,
new Type[] { typeof(string) }
);
ilg.Ldarg(0);
if (source == "Reader.ReadElementString()" || source == "Reader.ReadString()") {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_ReadXXXString = typeof(XmlReader).GetMethod(
source == "Reader.ReadElementString()" ? "ReadElementString" : "ReadString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadXXXString);
}
else if (source == "Reader.Value") {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod(
"get_Value",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Value);
}
else if (source == "vals[i]") {
LocalBuilder locVals = ilg.GetLocal("vals");
LocalBuilder locI = ilg.GetLocal("i");
ilg.LoadArrayElement(locVals, locI);
}
else if (source == "false") {
ilg.Ldc(false);
}
else {
throw CodeGenerator.NotSupported("Unexpected: " + source);
}
ilg.Call(methodBuilder);
}
else if (mapping.TypeDesc == StringTypeDesc) {
if (source == "Reader.ReadElementString()" || source == "Reader.ReadString()") {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_ReadXXXString = typeof(XmlReader).GetMethod(
source == "Reader.ReadElementString()" ? "ReadElementString" : "ReadString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadXXXString);
}
else if (source == "Reader.Value") {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod(
"get_Value",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Value);
}
else if (source == "vals[i]") {
LocalBuilder locVals = ilg.GetLocal("vals");
LocalBuilder locI = ilg.GetLocal("i");
ilg.LoadArrayElement(locVals, locI);
}
else {
throw CodeGenerator.NotSupported("Unexpected: " + source);
}
}
else if (mapping.TypeDesc.FormatterName == "String") {
if (source == "vals[i]") {
if (mapping.TypeDesc.CollapseWhitespace)
ilg.Ldarg(0);
LocalBuilder locVals = ilg.GetLocal("vals");
LocalBuilder locI = ilg.GetLocal("i");
ilg.LoadArrayElement(locVals, locI);
if (mapping.TypeDesc.CollapseWhitespace) {
MethodInfo XmlSerializationReader_CollapseWhitespace = typeof(XmlSerializationReader).GetMethod(
"CollapseWhitespace",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Call(XmlSerializationReader_CollapseWhitespace);
}
}
else {
System.Diagnostics.Debug.Assert(source == "Reader.Value" || source == "Reader.ReadElementString()");
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_method = typeof(XmlReader).GetMethod(
source == "Reader.Value" ? "get_Value" : "ReadElementString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
if (mapping.TypeDesc.CollapseWhitespace)
ilg.Ldarg(0);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_method);
if (mapping.TypeDesc.CollapseWhitespace) {
MethodInfo XmlSerializationReader_CollapseWhitespace = typeof(XmlSerializationReader).GetMethod(
"CollapseWhitespace",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Call(XmlSerializationReader_CollapseWhitespace);
}
}
}
else {
Type argType = source == "false" ? typeof(Boolean) : typeof(String);
MethodInfo ToXXX;
if (mapping.TypeDesc.HasCustomFormatter) {
// Only these methods below that is non Static and need to ldarg("this") for Call.
BindingFlags bindingFlags = CodeGenerator.StaticBindingFlags;
if ((mapping.TypeDesc.FormatterName == "ByteArrayBase64" && source == "false")
|| (mapping.TypeDesc.FormatterName == "ByteArrayHex" && source == "false")
|| (mapping.TypeDesc.FormatterName == "XmlQualifiedName")) {
bindingFlags = CodeGenerator.InstanceBindingFlags;
ilg.Ldarg(0);
}
ToXXX = typeof(XmlSerializationReader).GetMethod(
"To" + mapping.TypeDesc.FormatterName,
bindingFlags,
null,
new Type[] { argType },
null
);
}
else {
ToXXX = typeof(XmlConvert).GetMethod(
"To" + mapping.TypeDesc.FormatterName,
CodeGenerator.StaticBindingFlags,
null,
new Type[] { argType },
null
);
}
if (source == "Reader.ReadElementString()" || source == "Reader.ReadString()") {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_ReadXXXString = typeof(XmlReader).GetMethod(
source == "Reader.ReadElementString()" ? "ReadElementString" : "ReadString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadXXXString);
}
else if (source == "Reader.Value") {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod(
"get_Value",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Value);
}
else if (source == "vals[i]") {
LocalBuilder locVals = ilg.GetLocal("vals");
LocalBuilder locI = ilg.GetLocal("i");
ilg.LoadArrayElement(locVals, locI);
}
else {
System.Diagnostics.Debug.Assert(source == "false");
ilg.Ldc(false);
}
ilg.Call(ToXXX);
}
}
string MakeUnique(EnumMapping mapping, string name) {
string uniqueName = name;
object m = Enums[uniqueName];
if (m != null) {
if (m == mapping) {
// we already have created the hashtable
return null;
}
int i = 0;
while (m != null) {
i++;
uniqueName = name + i.ToString(CultureInfo.InvariantCulture);
m = Enums[uniqueName];
}
}
Enums.Add(uniqueName, mapping);
return uniqueName;
}
string WriteHashtable(EnumMapping mapping, string typeName, out MethodBuilder get_TableName) {
get_TableName = null;
CodeIdentifier.CheckValidIdentifier(typeName);
string propName = MakeUnique(mapping, typeName + "Values");
if (propName == null) return CodeIdentifier.GetCSharpName(typeName);
string memberName = MakeUnique(mapping, "_" + propName);
propName = CodeIdentifier.GetCSharpName(propName);
FieldBuilder fieldBuilder = this.typeBuilder.DefineField(
memberName,
typeof(Hashtable),
FieldAttributes.Private
);
PropertyBuilder propertyBuilder = this.typeBuilder.DefineProperty(
propName,
PropertyAttributes.None,
CallingConventions.HasThis,
typeof(Hashtable),
null, null, null, null, null);
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(
typeof(Hashtable),
"get_" + propName,
CodeGenerator.EmptyTypeArray,
CodeGenerator.EmptyStringArray,
MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.SpecialName);
ilg.Ldarg(0);
ilg.LoadMember(fieldBuilder);
ilg.Load(null);
ilg.If(Cmp.EqualTo);
ConstructorInfo Hashtable_ctor = typeof(Hashtable).GetConstructor(
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
LocalBuilder hLoc = ilg.DeclareLocal(typeof(Hashtable), "h");
ilg.New(Hashtable_ctor);
ilg.Stloc(hLoc);
ConstantMapping[] constants = mapping.Constants;
MethodInfo Hashtable_Add = typeof(Hashtable).GetMethod(
"Add",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Object), typeof(Object) },
null
);
for (int i = 0; i < constants.Length; i++) {
ilg.Ldloc(hLoc);
ilg.Ldstr(constants[i].XmlName);
ilg.Ldc(Enum.ToObject(mapping.TypeDesc.Type, constants[i].Value));
ilg.ConvertValue(mapping.TypeDesc.Type, typeof(long));
ilg.ConvertValue(typeof(long), typeof(Object));
ilg.Call(Hashtable_Add);
}
ilg.Ldarg(0);
ilg.Ldloc(hLoc);
ilg.StoreMember(fieldBuilder);
ilg.EndIf();
ilg.Ldarg(0);
ilg.LoadMember(fieldBuilder);
get_TableName = ilg.EndMethod();
propertyBuilder.SetGetMethod(get_TableName);
return propName;
}
void WriteEnumMethod(EnumMapping mapping) {
MethodBuilder get_TableName = null;
if (mapping.IsFlags)
WriteHashtable(mapping, mapping.TypeDesc.Name, out get_TableName);
string methodName = (string)MethodNames[mapping];
string fullTypeName = mapping.TypeDesc.CSharpName;
List<Type> argTypes = new List<Type>();
List<string> argNames = new List<string>();
Type returnType;
Type underlyingType;
returnType = mapping.TypeDesc.Type;
underlyingType = Enum.GetUnderlyingType(returnType);
argTypes.Add(typeof(string));
argNames.Add("s");
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(
returnType,
GetMethodBuilder(methodName),
argTypes.ToArray(),
argNames.ToArray(),
CodeGenerator.PrivateMethodAttributes);
ConstantMapping[] constants = mapping.Constants;
if (mapping.IsFlags) {
{
MethodInfo XmlSerializationReader_ToEnum = typeof(XmlSerializationReader).GetMethod(
"ToEnum",
CodeGenerator.StaticBindingFlags,
null,
new Type[] { typeof(String), typeof(Hashtable), typeof(String) },
null
);
ilg.Ldarg("s");
ilg.Ldarg(0);
Debug.Assert(get_TableName != null);
ilg.Call(get_TableName);
ilg.Ldstr(fullTypeName);
ilg.Call(XmlSerializationReader_ToEnum);
// XmlSerializationReader_ToEnum return long!
if (underlyingType != typeof(long)) {
ilg.ConvertValue(typeof(long), underlyingType);
}
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
}
else {
List<Label> caseLabels = new List<Label>();
List<object> retValues = new List<object>();
Label defaultLabel = ilg.DefineLabel();
Label endSwitchLabel = ilg.DefineLabel();
// This local is necessary; otherwise, it becomes if/else
LocalBuilder localTmp = ilg.GetTempLocal(typeof(string));
ilg.Ldarg("s");
ilg.Stloc(localTmp);
ilg.Ldloc(localTmp);
ilg.Brfalse(defaultLabel);
Hashtable cases = new Hashtable();
for (int i = 0; i < constants.Length; i++) {
ConstantMapping c = constants[i];
CodeIdentifier.CheckValidIdentifier(c.Name);
if (cases[c.XmlName] == null) {
cases[c.XmlName] = c.XmlName;
Label caseLabel = ilg.DefineLabel();
ilg.Ldloc(localTmp);
ilg.Ldstr(c.XmlName);
MethodInfo String_op_Equality = typeof(string).GetMethod(
"op_Equality",
CodeGenerator.StaticBindingFlags,
null,
new Type[] { typeof(string), typeof(string) },
null
);
ilg.Call(String_op_Equality);
ilg.Brtrue(caseLabel);
caseLabels.Add(caseLabel);
retValues.Add(Enum.ToObject(mapping.TypeDesc.Type, c.Value));
}
}
ilg.Br(defaultLabel);
// Case bodies
for (int i = 0; i < caseLabels.Count; i++) {
ilg.MarkLabel(caseLabels[i]);
ilg.Ldc(retValues[i]);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
MethodInfo XmlSerializationReader_CreateUnknownConstantException = typeof(XmlSerializationReader).GetMethod(
"CreateUnknownConstantException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(string), typeof(Type) },
null
);
// Default body
ilg.MarkLabel(defaultLabel);
ilg.Ldarg(0);
ilg.Ldarg("s");
// typeof(..)
ilg.Ldc(mapping.TypeDesc.Type);
ilg.Call(XmlSerializationReader_CreateUnknownConstantException);
ilg.Throw();
// End switch
ilg.MarkLabel(endSwitchLabel);
}
ilg.MarkLabel(ilg.ReturnLabel);
ilg.Ldloc(ilg.ReturnLocal);
ilg.EndMethod();
}
void WriteDerivedTypes(StructMapping mapping, bool isTypedReturn, string returnTypeName) {
for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
ilg.InitElseIf();
WriteQNameEqual("xsiType", derived.TypeName, derived.Namespace);
ilg.AndIf();
string methodName = ReferenceMapping(derived);
#if DEBUG
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, derived.TypeDesc.Name));
#endif
List<Type> argTypes = new List<Type>();
ilg.Ldarg(0);
if (derived.TypeDesc.IsNullable) {
ilg.Ldarg("isNullable");
argTypes.Add(typeof(Boolean));
}
ilg.Ldc(false);
argTypes.Add(typeof(Boolean));
MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
methodName,
CodeGenerator.PrivateMethodAttributes,
derived.TypeDesc.Type,
argTypes.ToArray()
);
ilg.Call(methodBuilder);
ilg.ConvertValue(methodBuilder.ReturnType, ilg.ReturnLocal.LocalType);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
WriteDerivedTypes(derived, isTypedReturn, returnTypeName);
}
}
void WriteEnumAndArrayTypes() {
foreach (TypeScope scope in Scopes) {
foreach (Mapping m in scope.TypeMappings) {
if (m is EnumMapping) {
EnumMapping mapping = (EnumMapping)m;
ilg.InitElseIf();
WriteQNameEqual("xsiType", mapping.TypeName, mapping.Namespace);
ilg.AndIf();
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod(
"ReadStartElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadStartElement);
string methodName = ReferenceMapping(mapping);
#if DEBUG
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, mapping.TypeDesc.Name));
#endif
LocalBuilder eLoc = ilg.DeclareOrGetLocal(typeof(object), "e");
MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
methodName,
CodeGenerator.PrivateMethodAttributes,
mapping.TypeDesc.Type,
new Type[] { typeof(string) }
);
MethodInfo XmlSerializationReader_CollapseWhitespace = typeof(XmlSerializationReader).GetMethod(
"CollapseWhitespace",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
MethodInfo XmlReader_ReadString = typeof(XmlReader).GetMethod(
"ReadString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Ldarg(0);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadString);
ilg.Call(XmlSerializationReader_CollapseWhitespace);
ilg.Call(methodBuilder);
ilg.ConvertValue(methodBuilder.ReturnType, eLoc.LocalType);
ilg.Stloc(eLoc);
MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod(
"ReadEndElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadEndElement);
ilg.Ldloc(eLoc);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
// Caller own calling ilg.EndIf();
}
else if (m is ArrayMapping) {
ArrayMapping mapping = (ArrayMapping)m;
if (mapping.TypeDesc.HasDefaultConstructor) {
ilg.InitElseIf();
WriteQNameEqual("xsiType", mapping.TypeName, mapping.Namespace);
ilg.AndIf();
ilg.EnterScope();
MemberMapping memberMapping = new MemberMapping();
memberMapping.TypeDesc = mapping.TypeDesc;
memberMapping.Elements = mapping.Elements;
string aVar = "a";
string zVar = "z";
Member member = new Member(this, aVar, zVar, 0, memberMapping);
TypeDesc td = mapping.TypeDesc;
LocalBuilder aLoc = ilg.DeclareLocal(mapping.TypeDesc.Type, aVar);
if (mapping.TypeDesc.IsValueType) {
RaCodeGen.ILGenForCreateInstance(ilg, td.Type, false, false);
}
else
ilg.Load(null);
ilg.Stloc(aLoc);
WriteArray(member.Source, member.ArrayName, mapping, false, false, -1, 0);
ilg.Ldloc(aLoc);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
ilg.ExitScope();
// Caller own calling ilg.EndIf();
}
}
}
}
}
void WriteNullableMethod(NullableMapping nullableMapping) {
string methodName = (string)MethodNames[nullableMapping];
ilg = new CodeGenerator(this.typeBuilder);
ilg.BeginMethod(
nullableMapping.TypeDesc.Type,
GetMethodBuilder(methodName),
new Type[] { typeof(Boolean) },
new string[] { "checkType" },
CodeGenerator.PrivateMethodAttributes);
LocalBuilder oLoc = ilg.DeclareLocal(nullableMapping.TypeDesc.Type, "o");
ilg.LoadAddress(oLoc);
ilg.InitObj(nullableMapping.TypeDesc.Type);
MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod(
"ReadNull",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadNull);
ilg.If();
{
ilg.Ldloc(oLoc);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
ilg.EndIf();
ElementAccessor element = new ElementAccessor();
element.Mapping = nullableMapping.BaseMapping;
element.Any = false;
element.IsNullable = nullableMapping.BaseMapping.TypeDesc.IsNullable;
WriteElement("o", null, null, element, null, null, false, false, -1, -1);
ilg.Ldloc(oLoc);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
ilg.MarkLabel(ilg.ReturnLabel);
ilg.Ldloc(ilg.ReturnLocal);
ilg.EndMethod();
}
void WriteStructMethod(StructMapping structMapping) {
WriteLiteralStructMethod(structMapping);
}
void WriteLiteralStructMethod(StructMapping structMapping) {
string methodName = (string)MethodNames[structMapping];
string typeName = structMapping.TypeDesc.CSharpName;
ilg = new CodeGenerator(this.typeBuilder);
List<Type> argTypes = new List<Type>();
List<string> argNames = new List<string>();
if (structMapping.TypeDesc.IsNullable) {
argTypes.Add(typeof(Boolean));
argNames.Add("isNullable");
}
argTypes.Add(typeof(Boolean));
argNames.Add("checkType");
ilg.BeginMethod(
structMapping.TypeDesc.Type,
GetMethodBuilder(methodName),
argTypes.ToArray(),
argNames.ToArray(),
CodeGenerator.PrivateMethodAttributes);
LocalBuilder locXsiType = ilg.DeclareLocal(typeof(XmlQualifiedName), "xsiType");
LocalBuilder locIsNull = ilg.DeclareLocal(typeof(Boolean), "isNull");
MethodInfo XmlSerializationReader_GetXsiType = typeof(XmlSerializationReader).GetMethod(
"GetXsiType",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod(
"ReadNull",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
Label labelTrue = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
ilg.Ldarg("checkType");
ilg.Brtrue(labelTrue);
ilg.Load(null);
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_GetXsiType);
ilg.MarkLabel(labelEnd);
ilg.Stloc(locXsiType);
ilg.Ldc(false);
ilg.Stloc(locIsNull);
if (structMapping.TypeDesc.IsNullable) {
ilg.Ldarg("isNullable");
ilg.If();
{
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadNull);
ilg.Stloc(locIsNull);
}
ilg.EndIf();
}
ilg.Ldarg("checkType");
ilg.If(); // if (checkType)
if (structMapping.TypeDesc.IsRoot) {
ilg.Ldloc(locIsNull);
ilg.If();
ilg.Ldloc(locXsiType);
ilg.Load(null);
ilg.If(Cmp.NotEqualTo);
MethodInfo XmlSerializationReader_ReadTypedNull = typeof(XmlSerializationReader).GetMethod(
"ReadTypedNull",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { locXsiType.LocalType },
null
);
ilg.Ldarg(0);
ilg.Ldloc(locXsiType);
ilg.Call(XmlSerializationReader_ReadTypedNull);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
ilg.Else();
if (structMapping.TypeDesc.IsValueType) {
throw CodeGenerator.NotSupported("Arg_NeverValueType");
}
else {
ilg.Load(null);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
ilg.EndIf(); // if (xsiType != null)
ilg.EndIf(); // if (isNull)
}
ilg.Ldloc(typeof(XmlQualifiedName), "xsiType");
ilg.Load(null);
ilg.Ceq();
if (!structMapping.TypeDesc.IsRoot) {
labelTrue = ilg.DefineLabel();
labelEnd = ilg.DefineLabel();
// xsiType == null
ilg.Brtrue(labelTrue);
WriteQNameEqual("xsiType", structMapping.TypeName, structMapping.Namespace);
// Bool result for WriteQNameEqual is on the stack
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldc(true);
ilg.MarkLabel(labelEnd);
}
ilg.If(); // if (xsiType == null
if (structMapping.TypeDesc.IsRoot) {
ConstructorInfo XmlQualifiedName_ctor = typeof(XmlQualifiedName).GetConstructor(
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(String) },
null
);
MethodInfo XmlSerializationReader_ReadTypedPrimitive = typeof(XmlSerializationReader).GetMethod(
"ReadTypedPrimitive",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(XmlQualifiedName) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(Soap.UrType);
ilg.Ldstr(XmlSchema.Namespace);
ilg.New(XmlQualifiedName_ctor);
ilg.Call(XmlSerializationReader_ReadTypedPrimitive);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
WriteDerivedTypes(structMapping, !structMapping.TypeDesc.IsRoot, typeName);
if (structMapping.TypeDesc.IsRoot) WriteEnumAndArrayTypes();
ilg.Else(); // if (xsiType == null
if (structMapping.TypeDesc.IsRoot) {
MethodInfo XmlSerializationReader_ReadTypedPrimitive = typeof(XmlSerializationReader).GetMethod(
"ReadTypedPrimitive",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { locXsiType.LocalType },
null
);
ilg.Ldarg(0);
ilg.Ldloc(locXsiType);
ilg.Call(XmlSerializationReader_ReadTypedPrimitive);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
else {
MethodInfo XmlSerializationReader_CreateUnknownTypeException = typeof(XmlSerializationReader).GetMethod(
"CreateUnknownTypeException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(XmlQualifiedName) },
null
);
ilg.Ldarg(0);
ilg.Ldloc(locXsiType);
ilg.Call(XmlSerializationReader_CreateUnknownTypeException);
ilg.Throw();
}
ilg.EndIf(); // if (xsiType == null
ilg.EndIf(); // checkType
if (structMapping.TypeDesc.IsNullable) {
ilg.Ldloc(typeof(bool), "isNull");
ilg.If();
{
ilg.Load(null);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
}
ilg.EndIf();
}
if (structMapping.TypeDesc.IsAbstract) {
MethodInfo XmlSerializationReader_CreateAbstractTypeException = typeof(XmlSerializationReader).GetMethod(
"CreateAbstractTypeException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(structMapping.TypeName);
ilg.Ldstr(structMapping.Namespace);
ilg.Call(XmlSerializationReader_CreateAbstractTypeException);
ilg.Throw();
}
else {
if (structMapping.TypeDesc.Type != null && typeof(XmlSchemaObject).IsAssignableFrom(structMapping.TypeDesc.Type)) {
MethodInfo XmlSerializationReader_set_DecodeName = typeof(XmlSerializationReader).GetMethod(
"set_DecodeName",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Boolean) },
null
);
ilg.Ldarg(0);
ilg.Ldc(false);
ilg.Call(XmlSerializationReader_set_DecodeName);
}
WriteCreateMapping(structMapping, "o");
LocalBuilder oLoc = ilg.GetLocal("o");
// this method populates the memberInfos dictionary based on the structMapping
MemberMapping[] mappings = TypeScope.GetSettableMembers(structMapping, memberInfos);
Member anyText = null;
Member anyElement = null;
Member anyAttribute = null;
bool isSequence = structMapping.HasExplicitSequence();
ArrayList arraysToDeclareList = new ArrayList(mappings.Length);
ArrayList arraysToSetList = new ArrayList(mappings.Length);
ArrayList allMembersList = new ArrayList(mappings.Length);
for (int i = 0; i < mappings.Length; i++) {
MemberMapping mapping = mappings[i];
CodeIdentifier.CheckValidIdentifier(mapping.Name);
string source = RaCodeGen.GetStringForMember("o", mapping.Name, structMapping.TypeDesc);
Member member = new Member(this, source, "a", i, mapping, GetChoiceIdentifierSource(mapping, "o", structMapping.TypeDesc));
if (!mapping.IsSequence)
member.ParamsReadSource = "paramsRead[" + i.ToString(CultureInfo.InvariantCulture) + "]";
member.IsNullable = mapping.TypeDesc.IsNullable;
if (mapping.CheckSpecified == SpecifiedAccessor.ReadWrite)
member.CheckSpecifiedSource = RaCodeGen.GetStringForMember("o", mapping.Name + "Specified", structMapping.TypeDesc);
if (mapping.Text != null)
anyText = member;
if (mapping.Attribute != null && mapping.Attribute.Any)
anyAttribute = member;
if (!isSequence) {
// find anyElement if present.
for (int j = 0; j < mapping.Elements.Length; j++) {
if (mapping.Elements[j].Any && (mapping.Elements[j].Name == null || mapping.Elements[j].Name.Length == 0)) {
anyElement = member;
break;
}
}
}
else if (mapping.IsParticle && !mapping.IsSequence) {
StructMapping declaringMapping;
structMapping.FindDeclaringMapping(mapping, out declaringMapping, structMapping.TypeName);
throw new InvalidOperationException(Res.GetString(Res.XmlSequenceHierarchy, structMapping.TypeDesc.FullName, mapping.Name, declaringMapping.TypeDesc.FullName, "Order"));
}
if (mapping.Attribute == null && mapping.Elements.Length == 1 && mapping.Elements[0].Mapping is ArrayMapping) {
Member arrayMember = new Member(this, source, source, "a", i, mapping, GetChoiceIdentifierSource(mapping, "o", structMapping.TypeDesc));
arrayMember.CheckSpecifiedSource = member.CheckSpecifiedSource;
allMembersList.Add(arrayMember);
}
else {
allMembersList.Add(member);
}
if (mapping.TypeDesc.IsArrayLike) {
arraysToDeclareList.Add(member);
if (mapping.TypeDesc.IsArrayLike && !(mapping.Elements.Length == 1 && mapping.Elements[0].Mapping is ArrayMapping)) {
member.ParamsReadSource = null; // flat arrays -- don't want to count params read.
if (member != anyText && member != anyElement) {
arraysToSetList.Add(member);
}
}
else if (!mapping.TypeDesc.IsArray) {
member.ParamsReadSource = null; // collection
}
}
}
if (anyElement != null) arraysToSetList.Add(anyElement);
if (anyText != null && anyText != anyElement) arraysToSetList.Add(anyText);
Member[] arraysToDeclare = (Member[])arraysToDeclareList.ToArray(typeof(Member));
Member[] arraysToSet = (Member[])arraysToSetList.ToArray(typeof(Member));
Member[] allMembers = (Member[])allMembersList.ToArray(typeof(Member));
WriteMemberBegin(arraysToDeclare);
WriteParamsRead(mappings.Length);
WriteAttributes(allMembers, anyAttribute, "UnknownNode", oLoc);
if (anyAttribute != null)
WriteMemberEnd(arraysToDeclare);
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_MoveToElement = typeof(XmlReader).GetMethod(
"MoveToElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToElement);
ilg.Pop();
MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod(
"get_IsEmptyElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_IsEmptyElement);
ilg.If();
MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
"Skip",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_Skip);
WriteMemberEnd(arraysToSet);
ilg.Ldloc(oLoc);
ilg.Stloc(ilg.ReturnLocal);
ilg.Br(ilg.ReturnLabel);
ilg.EndIf();
MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod(
"ReadStartElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadStartElement);
if (IsSequence(allMembers)) {
ilg.Ldc(0);
ilg.Stloc(typeof(Int32), "state");
}
int loopIndex = WriteWhileNotLoopStart();
string unknownNode = "UnknownNode((object)o, " + ExpectedElements(allMembers) + ");";
WriteMemberElements(allMembers, unknownNode, unknownNode, anyElement, anyText);
MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod(
"MoveToContent",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
WriteWhileLoopEnd(loopIndex);
WriteMemberEnd(arraysToSet);
MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod(
"ReadEndElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadEndElement);
ilg.Ldloc(structMapping.TypeDesc.Type, "o");
ilg.Stloc(ilg.ReturnLocal);
}
ilg.MarkLabel(ilg.ReturnLabel);
ilg.Ldloc(ilg.ReturnLocal);
ilg.EndMethod();
}
void WriteQNameEqual(string source, string name, string ns) {
WriteID(name);
WriteID(ns);
// This api assume the source is local member of XmlQualifiedName type
// It leaves bool result on the stack
MethodInfo XmlQualifiedName_get_Name = typeof(XmlQualifiedName).GetMethod(
"get_Name",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlQualifiedName_get_Namespace = typeof(XmlQualifiedName).GetMethod(
"get_Namespace",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
Label labelEnd = ilg.DefineLabel();
Label labelFalse = ilg.DefineLabel();
LocalBuilder sLoc = ilg.GetLocal(source);
ilg.Ldloc(sLoc);
ilg.Call(XmlQualifiedName_get_Name);
ilg.Ldarg(0);
ilg.LoadMember(idNameFields[name ?? String.Empty]);
ilg.Bne(labelFalse);
ilg.Ldloc(sLoc);
ilg.Call(XmlQualifiedName_get_Namespace);
ilg.Ldarg(0);
ilg.LoadMember(idNameFields[ns ?? String.Empty]);
ilg.Ceq();
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelFalse);
ilg.Ldc(false);
ilg.MarkLabel(labelEnd);
}
void WriteXmlNodeEqual(string source, string name, string ns) {
WriteXmlNodeEqual(source, name, ns, true);
}
void WriteXmlNodeEqual(string source, string name, string ns, bool doAndIf) {
bool isNameNullOrEmpty = string.IsNullOrEmpty(name);
if (!isNameNullOrEmpty) {
WriteID(name);
}
WriteID(ns);
// Only support Reader and XmlSerializationReaderReader only
System.Diagnostics.Debug.Assert(source == "Reader");
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_" + source,
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_LocalName = typeof(XmlReader).GetMethod(
"get_LocalName",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_NamespaceURI = typeof(XmlReader).GetMethod(
"get_NamespaceURI",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
Label labelFalse = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
if (!isNameNullOrEmpty) {
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_LocalName);
ilg.Ldarg(0);
ilg.LoadMember(idNameFields[name ?? String.Empty]);
ilg.Bne(labelFalse);
}
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NamespaceURI);
ilg.Ldarg(0);
ilg.LoadMember(idNameFields[ns ?? String.Empty]);
ilg.Ceq();
if (!isNameNullOrEmpty) {
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelFalse);
ilg.Ldc(false);
ilg.MarkLabel(labelEnd);
}
if (doAndIf)
ilg.AndIf();
}
void WriteID(string name) {
if (name == null) {
//Writer.Write("null");
//return;
name = "";
}
string idName = (string)idNames[name];
if (idName == null) {
idName = NextIdName(name);
idNames.Add(name, idName);
idNameFields.Add(name, this.typeBuilder.DefineField(idName, typeof(string), FieldAttributes.Private));
}
}
void WriteAttributes(Member[] members, Member anyAttribute, string elseCall, LocalBuilder firstParam) {
int count = 0;
Member xmlnsMember = null;
ArrayList attributes = new ArrayList();
// Condition do at the end, so C# looks the same
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_MoveToNextAttribute = typeof(XmlReader).GetMethod(
"MoveToNextAttribute",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.WhileBegin();
for (int i = 0; i < members.Length; i++) {
Member member = (Member)members[i];
if (member.Mapping.Xmlns != null) {
xmlnsMember = member;
continue;
}
if (member.Mapping.Ignore)
continue;
AttributeAccessor attribute = member.Mapping.Attribute;
if (attribute == null) continue;
if (attribute.Any) continue;
attributes.Add(attribute);
if (count++ > 0)
ilg.InitElseIf();
else
ilg.InitIf();
if (member.ParamsReadSource != null) {
ILGenParamsReadSource(member.ParamsReadSource);
ilg.Ldc(false);
ilg.AndIf(Cmp.EqualTo);
}
if (attribute.IsSpecialXmlNamespace) {
WriteXmlNodeEqual("Reader", attribute.Name, XmlReservedNs.NsXml);
}
else
WriteXmlNodeEqual("Reader", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "");
WriteAttribute(member);
}
if (count > 0)
ilg.InitElseIf();
else
ilg.InitIf();
if (xmlnsMember != null) {
MethodInfo XmlSerializationReader_IsXmlnsAttribute = typeof(XmlSerializationReader).GetMethod(
"IsXmlnsAttribute",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(string) },
null
);
MethodInfo XmlReader_get_Name = typeof(XmlReader).GetMethod(
"get_Name",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_LocalName = typeof(XmlReader).GetMethod(
"get_LocalName",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod(
"get_Value",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Name);
ilg.Call(XmlSerializationReader_IsXmlnsAttribute);
ilg.Ldc(true);
ilg.AndIf(Cmp.EqualTo);
ILGenLoad(xmlnsMember.Source);
ilg.Load(null);
ilg.If(Cmp.EqualTo);
WriteSourceBegin(xmlnsMember.Source);
ConstructorInfo ctor = xmlnsMember.Mapping.TypeDesc.Type.GetConstructor(
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.New(ctor);
WriteSourceEnd(xmlnsMember.Source, xmlnsMember.Mapping.TypeDesc.Type);
ilg.EndIf(); // if (xmlnsMember.Source == null
Label labelEqual5 = ilg.DefineLabel();
Label labelEndLength = ilg.DefineLabel();
MethodInfo Add = xmlnsMember.Mapping.TypeDesc.Type.GetMethod(
"Add",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(String) },
null
);
MethodInfo String_get_Length = typeof(String).GetMethod(
"get_Length",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ILGenLoad(xmlnsMember.ArraySource, xmlnsMember.Mapping.TypeDesc.Type);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Name);
ilg.Call(String_get_Length);
ilg.Ldc(5);
ilg.Beq(labelEqual5);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_LocalName);
ilg.Br(labelEndLength);
ilg.MarkLabel(labelEqual5);
ilg.Ldstr(String.Empty);
ilg.MarkLabel(labelEndLength);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Value);
ilg.Call(Add);
ilg.Else();
}
else {
MethodInfo XmlSerializationReader_IsXmlnsAttribute = typeof(XmlSerializationReader).GetMethod(
"IsXmlnsAttribute",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(string) },
null
);
MethodInfo XmlReader_get_Name = typeof(XmlReader).GetMethod(
"get_Name",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Name);
ilg.Call(XmlSerializationReader_IsXmlnsAttribute);
ilg.Ldc(false);
ilg.AndIf(Cmp.EqualTo);
}
if (anyAttribute != null) {
LocalBuilder localAttr = ilg.DeclareOrGetLocal(typeof(XmlAttribute), "attr");
MethodInfo XmlSerializationReader_get_Document = typeof(XmlSerializationReader).GetMethod(
"get_Document",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlDocument_ReadNode = typeof(XmlDocument).GetMethod(
"ReadNode",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(XmlReader) },
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Document);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlDocument_ReadNode);
ilg.ConvertValue(XmlDocument_ReadNode.ReturnType, localAttr.LocalType);
ilg.Stloc(localAttr);
MethodInfo XmlSerializationReader_ParseWsdlArrayType = typeof(XmlSerializationReader).GetMethod(
"ParseWsdlArrayType",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { localAttr.LocalType },
null
);
ilg.Ldarg(0);
ilg.Ldloc(localAttr);
ilg.Call(XmlSerializationReader_ParseWsdlArrayType);
WriteAttribute(anyAttribute);
}
else {
List<Type> argTypes = new List<Type>();
ilg.Ldarg(0);
argTypes.Add(typeof(object));
ilg.Ldloc(firstParam);
ilg.ConvertValue(firstParam.LocalType, typeof(object));
if (attributes.Count > 0) {
string qnames = "";
for (int i = 0; i < attributes.Count; i++) {
AttributeAccessor attribute = (AttributeAccessor)attributes[i];
if (i > 0)
qnames += ", ";
qnames += attribute.IsSpecialXmlNamespace ? XmlReservedNs.NsXml : (attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "") + ":" + attribute.Name;
}
argTypes.Add(typeof(string));
ilg.Ldstr(qnames);
}
System.Diagnostics.Debug.Assert(elseCall == "UnknownNode");
MethodInfo elseCallMethod = typeof(XmlSerializationReader).GetMethod(
elseCall,
CodeGenerator.InstanceBindingFlags,
null,
argTypes.ToArray(),
null
);
ilg.Call(elseCallMethod);
}
ilg.EndIf();
ilg.WhileBeginCondition();
{
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToNextAttribute);
}
ilg.WhileEndCondition();
ilg.WhileEnd();
}
void WriteAttribute(Member member) {
AttributeAccessor attribute = member.Mapping.Attribute;
if (attribute.Mapping is SpecialMapping) {
SpecialMapping special = (SpecialMapping)attribute.Mapping;
if (special.TypeDesc.Kind == TypeKind.Attribute) {
WriteSourceBegin(member.ArraySource);
ilg.Ldloc("attr");
WriteSourceEnd(member.ArraySource, member.Mapping.TypeDesc.IsArrayLike ? member.Mapping.TypeDesc.ArrayElementTypeDesc.Type : member.Mapping.TypeDesc.Type);
}
else if (special.TypeDesc.CanBeAttributeValue) {
LocalBuilder attrLoc = ilg.GetLocal("attr");
ilg.Ldloc(attrLoc);
// to get code compat
if (attrLoc.LocalType == typeof(XmlAttribute)) {
ilg.Load(null);
ilg.Cne();
}
else
ilg.IsInst(typeof(XmlAttribute));
ilg.If();
WriteSourceBegin(member.ArraySource);
ilg.Ldloc(attrLoc);
ilg.ConvertValue(attrLoc.LocalType, typeof(XmlAttribute));
WriteSourceEnd(member.ArraySource, member.Mapping.TypeDesc.IsArrayLike ? member.Mapping.TypeDesc.ArrayElementTypeDesc.Type : member.Mapping.TypeDesc.Type);
ilg.EndIf();
}
else
throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
}
else {
if (attribute.IsList) {
LocalBuilder locListValues = ilg.DeclareOrGetLocal(typeof(string), "listValues");
LocalBuilder locVals = ilg.DeclareOrGetLocal(typeof(string[]), "vals");
MethodInfo String_Split = typeof(String).GetMethod(
"Split",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Char[]) },
null
);
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod(
"get_Value",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_Value);
ilg.Stloc(locListValues);
ilg.Ldloc(locListValues);
ilg.Load(null);
ilg.Call(String_Split);
ilg.Stloc(locVals);
LocalBuilder localI = ilg.DeclareOrGetLocal(typeof(Int32), "i");
ilg.For(localI, 0, locVals);
string attributeSource = GetArraySource(member.Mapping.TypeDesc, member.ArrayName);
WriteSourceBegin(attributeSource);
WritePrimitive(attribute.Mapping, "vals[i]");
WriteSourceEnd(attributeSource, member.Mapping.TypeDesc.ArrayElementTypeDesc.Type);
ilg.EndFor();
}
else {
WriteSourceBegin(member.ArraySource);
WritePrimitive(attribute.Mapping, attribute.IsList ? "vals[i]" : "Reader.Value");
WriteSourceEnd(member.ArraySource, member.Mapping.TypeDesc.IsArrayLike ? member.Mapping.TypeDesc.ArrayElementTypeDesc.Type : member.Mapping.TypeDesc.Type);
}
}
if (member.Mapping.CheckSpecified == SpecifiedAccessor.ReadWrite && member.CheckSpecifiedSource != null && member.CheckSpecifiedSource.Length > 0) {
ILGenSet(member.CheckSpecifiedSource, true);
}
if (member.ParamsReadSource != null) {
ILGenParamsReadSource(member.ParamsReadSource, true);
}
}
void WriteMemberBegin(Member[] members) {
for (int i = 0; i < members.Length; i++) {
Member member = (Member)members[i];
if (member.IsArrayLike) {
string a = member.ArrayName;
string c = "c" + a;
TypeDesc typeDesc = member.Mapping.TypeDesc;
if (member.Mapping.TypeDesc.IsArray) {
WriteArrayLocalDecl(typeDesc.CSharpName,
a, "null", typeDesc);
ilg.Ldc(0);
ilg.Stloc(typeof(int), c);
if (member.Mapping.ChoiceIdentifier != null) {
WriteArrayLocalDecl(member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.CSharpName + "[]",
member.ChoiceArrayName, "null",
member.Mapping.ChoiceIdentifier.Mapping.TypeDesc);
ilg.Ldc(0);
ilg.Stloc(typeof(int), "c" + member.ChoiceArrayName);
}
}
else {
if (member.Source[member.Source.Length - 1] == '(' || member.Source[member.Source.Length - 1] == '{') {
WriteCreateInstance(a, typeDesc.CannotNew, typeDesc.Type);
WriteSourceBegin(member.Source);
ilg.Ldloc(ilg.GetLocal(a));
WriteSourceEnd(member.Source, typeDesc.Type);
}
else {
if (member.IsList && !member.Mapping.ReadOnly && member.Mapping.TypeDesc.IsNullable) {
// we need to new the Collections and ArrayLists
ILGenLoad(member.Source, typeof(object));
ilg.Load(null);
ilg.If(Cmp.EqualTo);
if (!member.Mapping.TypeDesc.HasDefaultConstructor) {
MethodInfo XmlSerializationReader_CreateReadOnlyCollectionException = typeof(XmlSerializationReader).GetMethod(
"CreateReadOnlyCollectionException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(member.Mapping.TypeDesc.CSharpName);
ilg.Call(XmlSerializationReader_CreateReadOnlyCollectionException);
ilg.Throw();
}
else {
WriteSourceBegin(member.Source);
RaCodeGen.ILGenForCreateInstance(ilg, member.Mapping.TypeDesc.Type, typeDesc.CannotNew, true);
WriteSourceEnd(member.Source, member.Mapping.TypeDesc.Type);
}
ilg.EndIf(); // if ((object)(member.Source) == null
}
WriteLocalDecl(a, new SourceInfo(member.Source, member.Source, member.Mapping.MemberInfo, member.Mapping.TypeDesc.Type, ilg));
}
}
}
}
}
string ExpectedElements(Member[] members) {
if (IsSequence(members))
return "null";
string qnames = string.Empty;
bool firstElement = true;
for (int i = 0; i < members.Length; i++) {
Member member = (Member)members[i];
if (member.Mapping.Xmlns != null)
continue;
if (member.Mapping.Ignore)
continue;
if (member.Mapping.IsText || member.Mapping.IsAttribute)
continue;
ElementAccessor[] elements = member.Mapping.Elements;
for (int j = 0; j < elements.Length; j++) {
ElementAccessor e = elements[j];
string ns = e.Form == XmlSchemaForm.Qualified ? e.Namespace : "";
if (e.Any && (e.Name == null || e.Name.Length == 0)) continue;
if (!firstElement)
qnames += ", ";
qnames += ns + ":" + e.Name;
firstElement = false;
}
}
return ReflectionAwareILGen.GetQuotedCSharpString(null, qnames);
}
void WriteMemberElements(Member[] members, string elementElseString, string elseString, Member anyElement, Member anyText) {
if (anyText != null) {
ilg.Load(null);
ilg.Stloc(typeof(string), "tmp");
}
MethodInfo XmlReader_get_NodeType = typeof(XmlReader).GetMethod(
"get_NodeType",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
int XmlNodeType_Element = 1;
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType_Element);
ilg.If(Cmp.EqualTo);
WriteMemberElementsIf(members, anyElement, elementElseString);
if (anyText != null)
WriteMemberText(anyText, elseString);
ilg.Else();
ILGenElseString(elseString);
ilg.EndIf();
}
void WriteMemberText(Member anyText, string elseString) {
ilg.InitElseIf();
Label labelTrue = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_NodeType = typeof(XmlReader).GetMethod(
"get_NodeType",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType.Text);
ilg.Ceq();
ilg.Brtrue(labelTrue);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType.CDATA);
ilg.Ceq();
ilg.Brtrue(labelTrue);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType.Whitespace);
ilg.Ceq();
ilg.Brtrue(labelTrue);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType.SignificantWhitespace);
ilg.Ceq();
ilg.Br(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldc(true);
ilg.MarkLabel(labelEnd);
ilg.AndIf();
if (anyText != null) {
WriteText(anyText);
}
Debug.Assert(anyText != null);
}
void WriteText(Member member) {
TextAccessor text = member.Mapping.Text;
if (text.Mapping is SpecialMapping) {
SpecialMapping special = (SpecialMapping)text.Mapping;
WriteSourceBeginTyped(member.ArraySource, special.TypeDesc);
switch (special.TypeDesc.Kind) {
case TypeKind.Node:
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_ReadString = typeof(XmlReader).GetMethod(
"ReadString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlSerializationReader_get_Document = typeof(XmlSerializationReader).GetMethod(
"get_Document",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlDocument_CreateTextNode = typeof(XmlDocument).GetMethod(
"CreateTextNode",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Document);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadString);
ilg.Call(XmlDocument_CreateTextNode);
break;
default:
throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
}
WriteSourceEnd(member.ArraySource, special.TypeDesc.Type);
}
else {
if (member.IsArrayLike) {
WriteSourceBegin(member.ArraySource);
if (text.Mapping.TypeDesc.CollapseWhitespace) {
ilg.Ldarg(0); // for calling CollapseWhitespace
}
else {
}
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_ReadString = typeof(XmlReader).GetMethod(
"ReadString",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadString);
if (text.Mapping.TypeDesc.CollapseWhitespace) {
MethodInfo XmlSerializationReader_CollapseWhitespace = typeof(XmlSerializationReader).GetMethod(
"CollapseWhitespace",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Call(XmlSerializationReader_CollapseWhitespace);
}
}
else {
if (text.Mapping.TypeDesc == StringTypeDesc || text.Mapping.TypeDesc.FormatterName == "String") {
LocalBuilder tmpLoc = ilg.GetLocal("tmp");
MethodInfo XmlSerializationReader_ReadString = typeof(XmlSerializationReader).GetMethod(
"ReadString",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(Boolean) },
null
);
ilg.Ldarg(0);
ilg.Ldloc(tmpLoc);
ilg.Ldc(text.Mapping.TypeDesc.CollapseWhitespace);
ilg.Call(XmlSerializationReader_ReadString);
ilg.Stloc(tmpLoc);
WriteSourceBegin(member.ArraySource);
ilg.Ldloc(tmpLoc);
}
else {
WriteSourceBegin(member.ArraySource);
WritePrimitive(text.Mapping, "Reader.ReadString()");
}
}
WriteSourceEnd(member.ArraySource, text.Mapping.TypeDesc.Type);
}
}
void WriteMemberElementsElse(Member anyElement, string elementElseString) {
if (anyElement != null) {
ElementAccessor[] elements = anyElement.Mapping.Elements;
for (int i = 0; i < elements.Length; i++) {
ElementAccessor element = elements[i];
if (element.Any && element.Name.Length == 0) {
WriteElement(anyElement.ArraySource, anyElement.ArrayName, anyElement.ChoiceArraySource, element, anyElement.Mapping.ChoiceIdentifier, anyElement.Mapping.CheckSpecified == SpecifiedAccessor.ReadWrite ? anyElement.CheckSpecifiedSource : null, false, false, -1, i);
break;
}
}
}
else {
ILGenElementElseString(elementElseString);
}
}
bool IsSequence(Member[] members) {
for (int i = 0; i < members.Length; i++) {
if (members[i].Mapping.IsParticle && members[i].Mapping.IsSequence)
return true;
}
return false;
}
void WriteMemberElementsIf(Member[] members, Member anyElement, string elementElseString) {
int count = 0;
bool isSequence = IsSequence(members);
int cases = 0;
for (int i = 0; i < members.Length; i++) {
Member member = (Member)members[i];
if (member.Mapping.Xmlns != null)
continue;
if (member.Mapping.Ignore)
continue;
if (isSequence && (member.Mapping.IsText || member.Mapping.IsAttribute))
continue;
bool firstElement = true;
ChoiceIdentifierAccessor choice = member.Mapping.ChoiceIdentifier;
ElementAccessor[] elements = member.Mapping.Elements;
for (int j = 0; j < elements.Length; j++) {
ElementAccessor e = elements[j];
string ns = e.Form == XmlSchemaForm.Qualified ? e.Namespace : "";
if (!isSequence && e.Any && (e.Name == null || e.Name.Length == 0)) continue;
if (!firstElement || (!isSequence && count > 0)) {
ilg.InitElseIf();
}
else if (isSequence) {
if (cases > 0)
ilg.InitElseIf();
else
ilg.InitIf();
ilg.Ldloc("state");
ilg.Ldc(cases);
ilg.AndIf(Cmp.EqualTo);
ilg.InitIf();
}
else {
ilg.InitIf();
}
count++;
firstElement = false;
if (member.ParamsReadSource != null) {
ILGenParamsReadSource(member.ParamsReadSource);
ilg.Ldc(false);
ilg.AndIf(Cmp.EqualTo);
}
Label labelTrue = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
if (member.Mapping.IsReturnValue) {
MethodInfo XmlSerializationReader_get_IsReturnValue = typeof(XmlSerializationReader).GetMethod(
"get_IsReturnValue",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_IsReturnValue);
ilg.Brtrue(labelTrue);
}
if (isSequence && e.Any && e.AnyNamespaces == null) {
ilg.Ldc(true);
}
else {
WriteXmlNodeEqual("Reader", e.Name, ns, false);
}
if (member.Mapping.IsReturnValue) {
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldc(true);
ilg.MarkLabel(labelEnd);
}
ilg.AndIf();
WriteElement(member.ArraySource, member.ArrayName, member.ChoiceArraySource, e, choice, member.Mapping.CheckSpecified == SpecifiedAccessor.ReadWrite ? member.CheckSpecifiedSource : null, member.IsList && member.Mapping.TypeDesc.IsNullable, member.Mapping.ReadOnly, member.FixupIndex, j);
if (member.Mapping.IsReturnValue) {
MethodInfo XmlSerializationReader_set_IsReturnValue = typeof(XmlSerializationReader).GetMethod(
"set_IsReturnValue",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Boolean) },
null
);
ilg.Ldarg(0);
ilg.Ldc(false);
ilg.Call(XmlSerializationReader_set_IsReturnValue);
}
if (member.ParamsReadSource != null) {
ILGenParamsReadSource(member.ParamsReadSource, true);
}
}
if (isSequence) {
if (member.IsArrayLike) {
ilg.Else();
}
else {
ilg.EndIf();
}
cases++;
ilg.Ldc(cases);
ilg.Stloc(ilg.GetLocal("state"));
if (member.IsArrayLike) {
ilg.EndIf();
}
}
}
if (count > 0) {
ilg.Else();
}
WriteMemberElementsElse(anyElement, elementElseString);
if (count > 0) {
ilg.EndIf();
}
}
string GetArraySource(TypeDesc typeDesc, string arrayName) {
return GetArraySource(typeDesc, arrayName, false);
}
string GetArraySource(TypeDesc typeDesc, string arrayName, bool multiRef) {
string a = arrayName;
string c = "c" + a;
string init = "";
if (multiRef) {
init = "soap = (System.Object[])EnsureArrayIndex(soap, " + c + "+2, typeof(System.Object)); ";
}
if (typeDesc.IsArray) {
string arrayTypeFullName = typeDesc.ArrayElementTypeDesc.CSharpName;
string castString = "(" + arrayTypeFullName + "[])";
init = init + a + " = " + castString +
"EnsureArrayIndex(" + a + ", " + c + ", " + RaCodeGen.GetStringForTypeof(arrayTypeFullName) + ");";
string arraySource = RaCodeGen.GetStringForArrayMember(a, c + "++", typeDesc);
if (multiRef) {
init = init + " soap[1] = " + a + ";";
init = init + " if (ReadReference(out soap[" + c + "+2])) " + arraySource + " = null; else ";
}
return init + arraySource;
}
else {
return RaCodeGen.GetStringForMethod(arrayName, typeDesc.CSharpName, "Add");
}
}
void WriteMemberEnd(Member[] members) {
WriteMemberEnd(members, false);
}
void WriteMemberEnd(Member[] members, bool soapRefs) {
for (int i = 0; i < members.Length; i++) {
Member member = (Member)members[i];
if (member.IsArrayLike) {
TypeDesc typeDesc = member.Mapping.TypeDesc;
if (typeDesc.IsArray) {
WriteSourceBegin(member.Source);
Debug.Assert(!soapRefs);
string a = member.ArrayName;
string c = "c" + a;
MethodInfo XmlSerializationReader_ShrinkArray = typeof(XmlSerializationReader).GetMethod(
"ShrinkArray",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Array), typeof(Int32), typeof(Type), typeof(Boolean) },
null
);
ilg.Ldarg(0);
ilg.Ldloc(ilg.GetLocal(a));
ilg.Ldloc(ilg.GetLocal(c));
ilg.Ldc(typeDesc.ArrayElementTypeDesc.Type);
ilg.Ldc(member.IsNullable);
ilg.Call(XmlSerializationReader_ShrinkArray);
ilg.ConvertValue(XmlSerializationReader_ShrinkArray.ReturnType, typeDesc.Type);
WriteSourceEnd(member.Source, typeDesc.Type);
if (member.Mapping.ChoiceIdentifier != null) {
WriteSourceBegin(member.ChoiceSource);
a = member.ChoiceArrayName;
c = "c" + a;
ilg.Ldarg(0);
ilg.Ldloc(ilg.GetLocal(a));
ilg.Ldloc(ilg.GetLocal(c));
ilg.Ldc(member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.Type);
ilg.Ldc(member.IsNullable);
ilg.Call(XmlSerializationReader_ShrinkArray);
ilg.ConvertValue(XmlSerializationReader_ShrinkArray.ReturnType, member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.Type.MakeArrayType());
WriteSourceEnd(member.ChoiceSource, member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.Type.MakeArrayType());
}
}
else if (typeDesc.IsValueType) {
LocalBuilder arrayLoc = ilg.GetLocal(member.ArrayName);
WriteSourceBegin(member.Source);
ilg.Ldloc(arrayLoc);
WriteSourceEnd(member.Source, arrayLoc.LocalType);
}
}
}
}
void WriteSourceBeginTyped(string source, TypeDesc typeDesc) {
WriteSourceBegin(source);
}
void WriteSourceBegin(string source) {
object variable;
if (ilg.TryGetVariable(source, out variable)) {
Type varType = ilg.GetVariableType(variable);
if (CodeGenerator.IsNullableGenericType(varType)) {
// local address to invoke ctor on WriteSourceEnd
ilg.LoadAddress(variable);
}
return;
}
// o.@Field
if (source.StartsWith("o.@", StringComparison.Ordinal)) {
ilg.LdlocAddress(ilg.GetLocal("o"));
return;
}
// a_0_0 = (global::System.Object[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Object));a_0_0[ca_0_0++]
Regex regex = NewRegex("(?<locA1>[^ ]+) = .+EnsureArrayIndex[(](?<locA2>[^,]+), (?<locI1>[^,]+),[^;]+;(?<locA3>[^[]+)[[](?<locI2>[^+]+)[+][+][]]");
Match match = regex.Match(source);
if (match.Success) {
Debug.Assert(match.Groups["locA1"].Value == match.Groups["locA2"].Value);
Debug.Assert(match.Groups["locA1"].Value == match.Groups["locA3"].Value);
Debug.Assert(match.Groups["locI1"].Value == match.Groups["locI2"].Value);
LocalBuilder localA = ilg.GetLocal(match.Groups["locA1"].Value);
LocalBuilder localI = ilg.GetLocal(match.Groups["locI1"].Value);
Type arrayElementType = localA.LocalType.GetElementType();
MethodInfo XmlSerializationReader_EnsureArrayIndex = typeof(XmlSerializationReader).GetMethod(
"EnsureArrayIndex",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Array), typeof(Int32), typeof(Type) },
null
);
ilg.Ldarg(0);
ilg.Ldloc(localA);
ilg.Ldloc(localI);
ilg.Ldc(arrayElementType);
ilg.Call(XmlSerializationReader_EnsureArrayIndex);
ilg.Castclass(localA.LocalType);
ilg.Stloc(localA);
// a_0[ca_0++]
ilg.Ldloc(localA);
ilg.Ldloc(localI);
ilg.Dup();
ilg.Ldc(1);
ilg.Add();
ilg.Stloc(localI);
if (CodeGenerator.IsNullableGenericType(arrayElementType) || arrayElementType.IsValueType) {
ilg.Ldelema(arrayElementType);
}
return;
}
//"a_0_0.Add("
if (source.EndsWith(".Add(", StringComparison.Ordinal)) {
int index = source.LastIndexOf(".Add(", StringComparison.Ordinal);
LocalBuilder localA = ilg.GetLocal(source.Substring(0, index));
ilg.LdlocAddress(localA);
return;
}
// p[0]
regex = NewRegex("(?<a>[^[]+)[[](?<ia>.+)[]]");
match = regex.Match(source);
if (match.Success) {
System.Diagnostics.Debug.Assert(ilg.GetVariableType(ilg.GetVariable(match.Groups["a"].Value)).IsArray);
ilg.Load(ilg.GetVariable(match.Groups["a"].Value));
ilg.Load(ilg.GetVariable(match.Groups["ia"].Value));
return;
}
throw CodeGenerator.NotSupported("Unexpected: " + source);
}
void WriteSourceEnd(string source, Type elementType) {
WriteSourceEnd(source, elementType, elementType);
}
void WriteSourceEnd(string source, Type elementType, Type stackType) {
object variable;
if (ilg.TryGetVariable(source, out variable)) {
Type varType = ilg.GetVariableType(variable);
if (CodeGenerator.IsNullableGenericType(varType)) {
ilg.Call(varType.GetConstructor(varType.GetGenericArguments()));
}
else {
Debug.Assert(elementType != null && variable is LocalBuilder);
ilg.ConvertValue(stackType, elementType);
ilg.ConvertValue(elementType, varType);
ilg.Stloc((LocalBuilder)variable);
}
return;
}
// o.@Field
if (source.StartsWith("o.@", StringComparison.Ordinal)) {
Debug.Assert(memberInfos.ContainsKey(source.Substring(3)));
MemberInfo memInfo = memberInfos[source.Substring(3)];
ilg.ConvertValue(stackType, memInfo.MemberType == MemberTypes.Field ? ((FieldInfo)memInfo).FieldType : ((PropertyInfo)memInfo).PropertyType);
ilg.StoreMember(memInfo);
return;
}
// a_0_0 = (global::System.Object[])EnsureArrayIndex(a_0_0, ca_0_0, typeof(global::System.Object));a_0_0[ca_0_0++]
Regex regex = NewRegex("(?<locA1>[^ ]+) = .+EnsureArrayIndex[(](?<locA2>[^,]+), (?<locI1>[^,]+),[^;]+;(?<locA3>[^[]+)[[](?<locI2>[^+]+)[+][+][]]");
Match match = regex.Match(source);
if (match.Success) {
object oVar = ilg.GetVariable(match.Groups["locA1"].Value);
Type arrayElementType = ilg.GetVariableType(oVar).GetElementType();
ilg.ConvertValue(elementType, arrayElementType);
if (CodeGenerator.IsNullableGenericType(arrayElementType) || arrayElementType.IsValueType) {
ilg.Stobj(arrayElementType);
}
else {
ilg.Stelem(arrayElementType);
}
return;
}
//"a_0_0.Add("
if (source.EndsWith(".Add(", StringComparison.Ordinal)) {
int index = source.LastIndexOf(".Add(", StringComparison.Ordinal);
LocalBuilder localA = ilg.GetLocal(source.Substring(0, index));
Debug.Assert(!localA.LocalType.IsGenericType || (localA.LocalType.GetGenericArguments().Length == 1 && localA.LocalType.GetGenericArguments()[0].IsAssignableFrom(elementType)));
MethodInfo Add = localA.LocalType.GetMethod(
"Add",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { elementType },
null
);
Debug.Assert(Add != null);
Type addParameterType = Add.GetParameters()[0].ParameterType;
ilg.ConvertValue(stackType, addParameterType);
ilg.Call(Add);
if (Add.ReturnType != typeof(void))
ilg.Pop();
return;
}
// p[0]
regex = NewRegex("(?<a>[^[]+)[[](?<ia>.+)[]]");
match = regex.Match(source);
if (match.Success) {
Type varType = ilg.GetVariableType(ilg.GetVariable(match.Groups["a"].Value));
System.Diagnostics.Debug.Assert(varType.IsArray);
Type varElementType = varType.GetElementType();
ilg.ConvertValue(stackType, varElementType);
ilg.Stelem(varElementType);
return;
}
throw CodeGenerator.NotSupported("Unexpected: " + source);
}
void WriteArray(string source, string arrayName, ArrayMapping arrayMapping, bool readOnly, bool isNullable, int fixupIndex, int elementIndex) {
MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod(
"ReadNull",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadNull);
ilg.IfNot();
MemberMapping memberMapping = new MemberMapping();
memberMapping.Elements = arrayMapping.Elements;
memberMapping.TypeDesc = arrayMapping.TypeDesc;
memberMapping.ReadOnly = readOnly;
if (source.StartsWith("o.@", StringComparison.Ordinal)) {
Debug.Assert(memberInfos.ContainsKey(source.Substring(3)));
memberMapping.MemberInfo = memberInfos[source.Substring(3)];
}
Member member = new Member(this, source, arrayName, elementIndex, memberMapping, false);
member.IsNullable = false;//Note, Microsoft: IsNullable is set to false since null condition (xsi:nil) is already handled by 'ReadNull()'
Member[] members = new Member[] { member };
WriteMemberBegin(members);
Label labelTrue = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
if (readOnly) {
ilg.Load(ilg.GetVariable(member.ArrayName));
ilg.Load(null);
ilg.Beq(labelTrue);
}
else {
}
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod(
"get_IsEmptyElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_IsEmptyElement);
if (readOnly) {
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldc(true);
ilg.MarkLabel(labelEnd);
}
ilg.If();
MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
"Skip",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_Skip);
ilg.Else();
MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod(
"ReadStartElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_ReadStartElement);
int loopIndex = WriteWhileNotLoopStart();
string unknownNode = "UnknownNode(null, " + ExpectedElements(members) + ");";
WriteMemberElements(members, unknownNode, unknownNode, null, null);
MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod(
"MoveToContent",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
WriteWhileLoopEnd(loopIndex);
MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod(
"ReadEndElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadEndElement);
ilg.EndIf();
WriteMemberEnd(members, false);
if (isNullable) {
ilg.Else();
member.IsNullable = true;
WriteMemberBegin(members);
WriteMemberEnd(members);
}
ilg.EndIf();
}
void WriteElement(string source, string arrayName, string choiceSource, ElementAccessor element, ChoiceIdentifierAccessor choice, string checkSpecified, bool checkForNull, bool readOnly, int fixupIndex, int elementIndex) {
if (checkSpecified != null && checkSpecified.Length > 0) {
ILGenSet(checkSpecified, true);
}
if (element.Mapping is ArrayMapping) {
WriteArray(source, arrayName, (ArrayMapping)element.Mapping, readOnly, element.IsNullable, fixupIndex, elementIndex);
}
else if (element.Mapping is NullableMapping) {
string methodName = ReferenceMapping(element.Mapping);
#if DEBUG
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, element.Mapping.TypeDesc.Name));
#endif
WriteSourceBegin(source);
ilg.Ldarg(0);
ilg.Ldc(true);
MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
methodName,
CodeGenerator.PrivateMethodAttributes,
// See WriteNullableMethod for different return type logic
element.Mapping.TypeDesc.Type,
new Type[] { typeof(Boolean) }
);
ilg.Call(methodBuilder);
WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
}
else if (element.Mapping is PrimitiveMapping) {
bool doEndIf = false;
if (element.IsNullable) {
MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod(
"ReadNull",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadNull);
ilg.If();
WriteSourceBegin(source);
if (element.Mapping.TypeDesc.IsValueType) {
throw CodeGenerator.NotSupported("No such condition. PrimitiveMapping && IsNullable = String, XmlQualifiedName and never IsValueType");
}
else {
ilg.Load(null);
}
WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
ilg.Else();
doEndIf = true;
}
if (element.Default != null && element.Default != DBNull.Value && element.Mapping.TypeDesc.IsValueType) {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod(
"get_IsEmptyElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_IsEmptyElement);
ilg.If();
MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
"Skip",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_Skip);
ilg.Else();
doEndIf = true;
}
else {
}
//For backward compatibiity
//When using old serializer, the serialized TimeSpan value is empty string
if (LocalAppContextSwitches.EnableTimeSpanSerialization && element.Mapping.TypeDesc.Type == typeof(TimeSpan))
{
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod(
"get_IsEmptyElement",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_IsEmptyElement);
ilg.If();
WriteSourceBegin(source);
MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
"Skip",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_Skip);
ConstructorInfo TimeSpan_ctor = typeof(TimeSpan).GetConstructor(
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Int64) },
null
);
ilg.Ldc(default(TimeSpan).Ticks);
ilg.New(TimeSpan_ctor);
WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
ilg.Else();
WriteSourceBegin(source);
WritePrimitive(element.Mapping, "Reader.ReadElementString()");
WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
ilg.EndIf();
}
else
{
WriteSourceBegin(source);
if (element.Mapping.TypeDesc == QnameTypeDesc) {
MethodInfo XmlSerializationReader_ReadElementQualifiedName = typeof(XmlSerializationReader).GetMethod(
"ReadElementQualifiedName",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_ReadElementQualifiedName);
}
else {
string readFunc;
switch (element.Mapping.TypeDesc.FormatterName) {
case "ByteArrayBase64":
case "ByteArrayHex":
readFunc = "false";
break;
default:
readFunc = "Reader.ReadElementString()";
break;
}
WritePrimitive(element.Mapping, readFunc);
}
WriteSourceEnd(source, element.Mapping.TypeDesc.Type);
}
if (doEndIf)
ilg.EndIf();
}
else if (element.Mapping is StructMapping) {
TypeMapping mapping = element.Mapping;
string methodName = ReferenceMapping(mapping);
#if DEBUG
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
if (methodName == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorMethod, mapping.TypeDesc.Name));
#endif
if (checkForNull) {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod(
"Skip",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldloc(arrayName);
ilg.Load(null);
ilg.If(Cmp.EqualTo);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_Skip);
ilg.Else();
}
WriteSourceBegin(source);
List<Type> argTypes = new List<Type>();
ilg.Ldarg(0);
if (mapping.TypeDesc.IsNullable) {
ilg.Load(element.IsNullable);
argTypes.Add(typeof(Boolean));
}
ilg.Ldc(true);
argTypes.Add(typeof(Boolean));
MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder,
methodName,
CodeGenerator.PrivateMethodAttributes,
mapping.TypeDesc.Type,
argTypes.ToArray()
);
ilg.Call(methodBuilder);
WriteSourceEnd(source, mapping.TypeDesc.Type);
if (checkForNull)
// 'If' begins in checkForNull above
ilg.EndIf();
}
else if (element.Mapping is SpecialMapping) {
SpecialMapping special = (SpecialMapping)element.Mapping;
switch (special.TypeDesc.Kind) {
case TypeKind.Node:
bool isDoc = special.TypeDesc.FullName == typeof(XmlDocument).FullName;
WriteSourceBeginTyped(source, special.TypeDesc);
MethodInfo XmlSerializationReader_ReadXmlXXX = typeof(XmlSerializationReader).GetMethod(
isDoc ? "ReadXmlDocument" : "ReadXmlNode",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Boolean) },
null
);
ilg.Ldarg(0);
ilg.Ldc(element.Any ? false : true);
ilg.Call(XmlSerializationReader_ReadXmlXXX);
// See logic in WriteSourceBeginTyped whether or not to castclass.
if (special.TypeDesc != null)
ilg.Castclass(special.TypeDesc.Type);
WriteSourceEnd(source, special.TypeDesc.Type);
break;
case TypeKind.Serializable:
SerializableMapping sm = (SerializableMapping)element.Mapping;
// check to see if we need to do the derivation
if (sm.DerivedMappings != null) {
MethodInfo XmlSerializationReader_GetXsiType = typeof(XmlSerializationReader).GetMethod(
"GetXsiType",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
Label labelTrue = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
LocalBuilder tserLoc = ilg.DeclareOrGetLocal(typeof(XmlQualifiedName), "tser");
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_GetXsiType);
ilg.Stloc(tserLoc);
ilg.Ldloc(tserLoc);
ilg.Load(null);
ilg.Ceq();
ilg.Brtrue(labelTrue);
WriteQNameEqual("tser", sm.XsiType.Name, sm.XsiType.Namespace);
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldc(true);
ilg.MarkLabel(labelEnd);
ilg.If();
}
WriteSourceBeginTyped(source, sm.TypeDesc);
bool isWrappedAny = !element.Any && IsWildcard(sm);
MethodInfo XmlSerializationReader_ReadSerializable = typeof(XmlSerializationReader).GetMethod(
"ReadSerializable",
CodeGenerator.InstanceBindingFlags,
null,
isWrappedAny ? new Type[] { typeof(IXmlSerializable), typeof(Boolean) } : new Type[] { typeof(IXmlSerializable) },
null
);
ilg.Ldarg(0);
RaCodeGen.ILGenForCreateInstance(ilg, sm.TypeDesc.Type, sm.TypeDesc.CannotNew, false);
if (sm.TypeDesc.CannotNew)
ilg.ConvertValue(typeof(object), typeof(IXmlSerializable));
if (isWrappedAny)
ilg.Ldc(true);
ilg.Call(XmlSerializationReader_ReadSerializable);
// See logic in WriteSourceBeginTyped whether or not to castclass.
if (sm.TypeDesc != null)
ilg.ConvertValue(typeof(IXmlSerializable), sm.TypeDesc.Type);
WriteSourceEnd(source, sm.TypeDesc.Type);
if (sm.DerivedMappings != null) {
WriteDerivedSerializable(sm, sm, source, isWrappedAny);
WriteUnknownNode("UnknownNode", "null", null, true);
}
break;
default:
throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
}
}
else {
throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
}
if (choice != null) {
#if DEBUG
// use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
if (choiceSource == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "need parent for the " + source));
#endif
WriteSourceBegin(choiceSource);
CodeIdentifier.CheckValidIdentifier(choice.MemberIds[elementIndex]);
RaCodeGen.ILGenForEnumMember(ilg, choice.Mapping.TypeDesc.Type, choice.MemberIds[elementIndex]);
WriteSourceEnd(choiceSource, choice.Mapping.TypeDesc.Type);
}
}
void WriteDerivedSerializable(SerializableMapping head, SerializableMapping mapping, string source, bool isWrappedAny) {
if (mapping == null)
return;
for (SerializableMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
Label labelTrue = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
LocalBuilder tserLoc = ilg.GetLocal("tser");
ilg.InitElseIf();
ilg.Ldloc(tserLoc);
ilg.Load(null);
ilg.Ceq();
ilg.Brtrue(labelTrue);
WriteQNameEqual("tser", derived.XsiType.Name, derived.XsiType.Namespace);
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelTrue);
ilg.Ldc(true);
ilg.MarkLabel(labelEnd);
ilg.AndIf();
if (derived.Type != null) {
if (head.Type.IsAssignableFrom(derived.Type)) {
WriteSourceBeginTyped(source, head.TypeDesc);
MethodInfo XmlSerializationReader_ReadSerializable = typeof(XmlSerializationReader).GetMethod(
"ReadSerializable",
CodeGenerator.InstanceBindingFlags,
null,
isWrappedAny ? new Type[] { typeof(IXmlSerializable), typeof(Boolean) } : new Type[] { typeof(IXmlSerializable) },
null
);
ilg.Ldarg(0);
RaCodeGen.ILGenForCreateInstance(ilg, derived.TypeDesc.Type, derived.TypeDesc.CannotNew, false);
if (derived.TypeDesc.CannotNew)
ilg.ConvertValue(typeof(object), typeof(IXmlSerializable));
if (isWrappedAny)
ilg.Ldc(true);
ilg.Call(XmlSerializationReader_ReadSerializable);
// See logic in WriteSourceBeginTyped whether or not to castclass.
if (head.TypeDesc != null)
ilg.ConvertValue(typeof(IXmlSerializable), head.TypeDesc.Type);
WriteSourceEnd(source, head.TypeDesc.Type);
}
else {
MethodInfo XmlSerializationReader_CreateBadDerivationException = typeof(XmlSerializationReader).GetMethod(
"CreateBadDerivationException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(String), typeof(String), typeof(String), typeof(String), typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(derived.XsiType.Name);
ilg.Ldstr(derived.XsiType.Namespace);
ilg.Ldstr(head.XsiType.Name);
ilg.Ldstr(head.XsiType.Namespace);
ilg.Ldstr(derived.Type.FullName);
ilg.Ldstr(head.Type.FullName);
ilg.Call(XmlSerializationReader_CreateBadDerivationException);
ilg.Throw();
}
}
else {
MethodInfo XmlSerializationReader_CreateMissingIXmlSerializableType = typeof(XmlSerializationReader).GetMethod(
"CreateMissingIXmlSerializableType",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String), typeof(String), typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(derived.XsiType.Name);
ilg.Ldstr(derived.XsiType.Namespace);
ilg.Ldstr(head.Type.FullName);
ilg.Call(XmlSerializationReader_CreateMissingIXmlSerializableType);
ilg.Throw();
}
WriteDerivedSerializable(head, derived, source, isWrappedAny);
}
}
int WriteWhileNotLoopStart() {
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod(
"MoveToContent",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_MoveToContent);
ilg.Pop();
int loopIndex = WriteWhileLoopStartCheck();
ilg.WhileBegin();
return loopIndex;
}
void WriteWhileLoopEnd(int loopIndex) {
WriteWhileLoopEndCheck(loopIndex);
ilg.WhileBeginCondition();
{
int XmlNodeType_None = 0;
//int XmlNodeType_Element = 1;
int XmlNodeType_EndElement = 15;
MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod(
"get_Reader",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
MethodInfo XmlReader_get_NodeType = typeof(XmlReader).GetMethod(
"get_NodeType",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
Label labelFalse = ilg.DefineLabel();
Label labelEnd = ilg.DefineLabel();
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType_EndElement);
ilg.Beq(labelFalse);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_Reader);
ilg.Call(XmlReader_get_NodeType);
ilg.Ldc(XmlNodeType_None);
ilg.Cne();
ilg.Br_S(labelEnd);
ilg.MarkLabel(labelFalse);
ilg.Ldc(false);
ilg.MarkLabel(labelEnd);
}
ilg.WhileEndCondition();
ilg.WhileEnd();
}
int WriteWhileLoopStartCheck() {
MethodInfo XmlSerializationReader_get_ReaderCount = typeof(XmlSerializationReader).GetMethod(
"get_ReaderCount",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldc(0);
ilg.Stloc(typeof(Int32), String.Format(CultureInfo.InvariantCulture, "whileIterations{0}", nextWhileLoopIndex));
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_get_ReaderCount);
ilg.Stloc(typeof(Int32), String.Format(CultureInfo.InvariantCulture, "readerCount{0}", nextWhileLoopIndex));
return nextWhileLoopIndex++;
}
void WriteWhileLoopEndCheck(int loopIndex) {
Type refIntType = Type.GetType("System.Int32&");
MethodInfo XmlSerializationReader_CheckReaderCount = typeof(XmlSerializationReader).GetMethod(
"CheckReaderCount",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { refIntType, refIntType },
null
);
ilg.Ldarg(0);
ilg.Ldloca(ilg.GetLocal(String.Format(CultureInfo.InvariantCulture, "whileIterations{0}", loopIndex)));
ilg.Ldloca(ilg.GetLocal(String.Format(CultureInfo.InvariantCulture, "readerCount{0}", loopIndex)));
ilg.Call(XmlSerializationReader_CheckReaderCount);
}
void WriteParamsRead(int length) {
LocalBuilder paramsRead = ilg.DeclareLocal(typeof(Boolean[]), "paramsRead");
ilg.NewArray(typeof(Boolean), length);
ilg.Stloc(paramsRead);
}
void WriteCreateMapping(TypeMapping mapping, string local) {
string fullTypeName = mapping.TypeDesc.CSharpName;
bool ctorInaccessible = mapping.TypeDesc.CannotNew;
LocalBuilder loc = ilg.DeclareLocal(
mapping.TypeDesc.Type,
local);
if (ctorInaccessible) {
ilg.BeginExceptionBlock();
}
RaCodeGen.ILGenForCreateInstance(ilg, mapping.TypeDesc.Type, mapping.TypeDesc.CannotNew, true);
ilg.Stloc(loc);
if (ctorInaccessible) {
ilg.Leave();
WriteCatchException(typeof(MissingMethodException));
MethodInfo XmlSerializationReader_CreateInaccessibleConstructorException = typeof(XmlSerializationReader).GetMethod(
"CreateInaccessibleConstructorException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(fullTypeName);
ilg.Call(XmlSerializationReader_CreateInaccessibleConstructorException);
ilg.Throw();
WriteCatchException(typeof(SecurityException));
MethodInfo XmlSerializationReader_CreateCtorHasSecurityException = typeof(XmlSerializationReader).GetMethod(
"CreateCtorHasSecurityException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldstr(fullTypeName);
ilg.Call(XmlSerializationReader_CreateCtorHasSecurityException);
ilg.Throw();
ilg.EndExceptionBlock();
}
}
void WriteCatchException(Type exceptionType) {
ilg.BeginCatchBlock(exceptionType);
ilg.Pop();
}
void WriteCatchCastException(TypeDesc typeDesc, string source, string id) {
WriteCatchException(typeof(InvalidCastException));
MethodInfo XmlSerializationReader_CreateInvalidCastException = typeof(XmlSerializationReader).GetMethod(
"CreateInvalidCastException",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(Type), typeof(Object), typeof(String) },
null
);
ilg.Ldarg(0);
ilg.Ldc(typeDesc.Type);
// GetTarget(ids[0])
if (source.StartsWith("GetTarget(ids[", StringComparison.Ordinal)) {
MethodInfo XmlSerializationReader_GetTarget = typeof(XmlSerializationReader).GetMethod(
"GetTarget",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(String) },
null
);
object idsLoc = ilg.GetVariable("ids");
ilg.Ldarg(0);
// Parse index
ilg.LoadArrayElement(idsLoc, Int32.Parse(source.Substring(14, source.Length - 16), CultureInfo.InvariantCulture));
ilg.Call(XmlSerializationReader_GetTarget);
}
else {
ilg.Load(ilg.GetVariable(source));
}
if (id == null)
ilg.Load(null);
else {
// ids[0]
if (id.StartsWith("ids[", StringComparison.Ordinal)) {
object idsLoc = ilg.GetVariable("ids");
// Parse index
ilg.LoadArrayElement(idsLoc, Int32.Parse(id.Substring(4, id.Length - 5), CultureInfo.InvariantCulture));
}
else {
object idVar = ilg.GetVariable(id);
ilg.Load(idVar);
ilg.ConvertValue(ilg.GetVariableType(idVar), typeof(string));
}
}
ilg.Call(XmlSerializationReader_CreateInvalidCastException);
ilg.Throw();
}
void WriteArrayLocalDecl(string typeName, string variableName, string initValue, TypeDesc arrayTypeDesc) {
RaCodeGen.WriteArrayLocalDecl(typeName, variableName, new SourceInfo(initValue, initValue, null, arrayTypeDesc.Type, ilg), arrayTypeDesc);
}
void WriteCreateInstance(string source, bool ctorInaccessible, Type type) {
RaCodeGen.WriteCreateInstance(source, ctorInaccessible, type, ilg);
}
void WriteLocalDecl(string variableName, SourceInfo initValue) {
RaCodeGen.WriteLocalDecl(variableName, initValue);
}
void ILGenElseString(string elseString) {
MethodInfo XmlSerializationReader_UnknownNode1 = typeof(XmlSerializationReader).GetMethod(
"UnknownNode",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(object) },
null
);
MethodInfo XmlSerializationReader_UnknownNode2 = typeof(XmlSerializationReader).GetMethod(
"UnknownNode",
CodeGenerator.InstanceBindingFlags,
null,
new Type[] { typeof(object), typeof(string) },
null
);
// UnknownNode(null, @":anyType");
Regex regex = NewRegex("UnknownNode[(]null, @[\"](?<qnames>[^\"]*)[\"][)];");
Match match = regex.Match(elseString);
if (match.Success) {
ilg.Ldarg(0);
ilg.Load(null);
ilg.Ldstr(match.Groups["qnames"].Value);
ilg.Call(XmlSerializationReader_UnknownNode2);
return;
}
// UnknownNode((object)o, @"");
regex = NewRegex("UnknownNode[(][(]object[)](?<o>[^,]+), @[\"](?<qnames>[^\"]*)[\"][)];");
match = regex.Match(elseString);
if (match.Success) {
ilg.Ldarg(0);
LocalBuilder localO = ilg.GetLocal(match.Groups["o"].Value);
ilg.Ldloc(localO);
ilg.ConvertValue(localO.LocalType, typeof(object));
ilg.Ldstr(match.Groups["qnames"].Value);
ilg.Call(XmlSerializationReader_UnknownNode2);
return;
}
// UnknownNode((object)o, null);
regex = NewRegex("UnknownNode[(][(]object[)](?<o>[^,]+), null[)];");
match = regex.Match(elseString);
if (match.Success) {
ilg.Ldarg(0);
LocalBuilder localO = ilg.GetLocal(match.Groups["o"].Value);
ilg.Ldloc(localO);
ilg.ConvertValue(localO.LocalType, typeof(object));
ilg.Load(null);
ilg.Call(XmlSerializationReader_UnknownNode2);
return;
}
// "UnknownNode((object)o);"
regex = NewRegex("UnknownNode[(][(]object[)](?<o>[^)]+)[)];");
match = regex.Match(elseString);
if (match.Success) {
ilg.Ldarg(0);
LocalBuilder localO = ilg.GetLocal(match.Groups["o"].Value);
ilg.Ldloc(localO);
ilg.ConvertValue(localO.LocalType, typeof(object));
ilg.Call(XmlSerializationReader_UnknownNode1);
return;
}
throw CodeGenerator.NotSupported("Unexpected: " + elseString);
}
void ILGenParamsReadSource(string paramsReadSource) {
Regex regex = NewRegex("paramsRead\\[(?<index>[0-9]+)\\]");
Match match = regex.Match(paramsReadSource);
if (match.Success) {
ilg.LoadArrayElement(ilg.GetLocal("paramsRead"), Int32.Parse(match.Groups["index"].Value, CultureInfo.InvariantCulture));
return;
}
throw CodeGenerator.NotSupported("Unexpected: " + paramsReadSource);
}
void ILGenParamsReadSource(string paramsReadSource, bool value) {
Regex regex = NewRegex("paramsRead\\[(?<index>[0-9]+)\\]");
Match match = regex.Match(paramsReadSource);
if (match.Success) {
ilg.StoreArrayElement(ilg.GetLocal("paramsRead"), Int32.Parse(match.Groups["index"].Value, CultureInfo.InvariantCulture), value);
return;
}
throw CodeGenerator.NotSupported("Unexpected: " + paramsReadSource);
}
void ILGenElementElseString(string elementElseString) {
if (elementElseString == "throw CreateUnknownNodeException();") {
MethodInfo XmlSerializationReader_CreateUnknownNodeException = typeof(XmlSerializationReader).GetMethod(
"CreateUnknownNodeException",
CodeGenerator.InstanceBindingFlags,
null,
CodeGenerator.EmptyTypeArray,
null
);
ilg.Ldarg(0);
ilg.Call(XmlSerializationReader_CreateUnknownNodeException);
ilg.Throw();
return;
}
if (elementElseString.StartsWith("UnknownNode(", StringComparison.Ordinal)) {
ILGenElseString(elementElseString);
return;
}
throw CodeGenerator.NotSupported("Unexpected: " + elementElseString);
}
void ILGenSet(string source, object value) {
WriteSourceBegin(source);
ilg.Load(value);
WriteSourceEnd(source, value == null ? typeof(object) : value.GetType());
}
}
}
|