private void WriteElements(SourceInfo source, string enumSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, string arrayName, bool writeAccessors, bool isNullable) { if (elements.Length == 0 && text == null) return; if (elements.Length == 1 && text == null) { TypeDesc td = elements[0].IsUnbounded ? elements[0].Mapping.TypeDesc.CreateArrayTypeDesc() : elements[0].Mapping.TypeDesc; if (!elements[0].Any && !elements[0].Mapping.TypeDesc.IsOptionalValue) source = source.CastTo(td); WriteElement(source, elements[0], arrayName, writeAccessors); } else { bool doEndIf = false; if (isNullable && choice == null) { source.Load(typeof(object)); ilg.Load(null); ilg.If(Cmp.NotEqualTo); doEndIf = true; } int anyCount = 0; ArrayList namedAnys = new ArrayList(); ElementAccessor unnamedAny = null; // can only have one bool wroteFirstIf = false; string enumTypeName = choice == null ? null : choice.Mapping.TypeDesc.FullName; for (int i = 0; i < elements.Length; i++) { ElementAccessor element = elements[i]; if (element.Any) { anyCount++; if (element.Name != null && element.Name.Length > 0) namedAnys.Add(element); else if (unnamedAny == null) unnamedAny = element; } else if (choice != null) { string fullTypeName = element.Mapping.TypeDesc.CSharpName; object enumValue; string enumFullName = enumTypeName + ".@" + FindChoiceEnumValue(element, (EnumMapping)choice.Mapping, out enumValue); if (wroteFirstIf) ilg.InitElseIf(); else { wroteFirstIf = true; ilg.InitIf(); } ILGenLoad(enumSource, choice == null ? null : choice.Mapping.TypeDesc.Type); ilg.Load(enumValue); ilg.Ceq(); if (isNullable && !element.IsNullable) { Label labelFalse = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); ilg.Brfalse(labelFalse); source.Load(typeof(object)); ilg.Load(null); ilg.Cne(); ilg.Br_S(labelEnd); ilg.MarkLabel(labelFalse); ilg.Ldc(false); ilg.MarkLabel(labelEnd); } ilg.AndIf(); WriteChoiceTypeCheck(source, fullTypeName, choice, enumFullName, element.Mapping.TypeDesc); SourceInfo castedSource = source; castedSource = source.CastTo(element.Mapping.TypeDesc); WriteElement(element.Any ? source : castedSource, element, arrayName, writeAccessors); } else { TypeDesc td = element.IsUnbounded ? element.Mapping.TypeDesc.CreateArrayTypeDesc() : element.Mapping.TypeDesc; string fullTypeName = td.CSharpName; if (wroteFirstIf) ilg.InitElseIf(); else { wroteFirstIf = true; ilg.InitIf(); } WriteInstanceOf(source, td.Type); // WriteInstanceOf leave bool on the stack ilg.AndIf(); SourceInfo castedSource = source; castedSource = source.CastTo(td); WriteElement(element.Any ? source : castedSource, element, arrayName, writeAccessors); } } if (wroteFirstIf) { if (anyCount > 0) { // See "else " below if (elements.Length - anyCount > 0) { // NOOP } else ilg.EndIf(); } } if (anyCount > 0) { if (elements.Length - anyCount > 0) ilg.InitElseIf(); else ilg.InitIf(); string fullTypeName = typeof(XmlElement).FullName; source.Load(typeof(object)); ilg.IsInst(typeof(XmlElement)); ilg.Load(null); ilg.Cne(); ilg.AndIf(); LocalBuilder elemLoc = ilg.DeclareLocal(typeof(XmlElement), "elem"); source.Load(typeof(XmlElement)); ilg.Stloc(elemLoc); int c = 0; foreach (ElementAccessor element in namedAnys) { if (c++ > 0) ilg.InitElseIf(); else ilg.InitIf(); string enumFullName = null; Label labelEnd, labelFalse; if (choice != null) { object enumValue; enumFullName = enumTypeName + ".@" + FindChoiceEnumValue(element, (EnumMapping)choice.Mapping, out enumValue); labelFalse = ilg.DefineLabel(); labelEnd = ilg.DefineLabel(); ILGenLoad(enumSource, choice == null ? null : choice.Mapping.TypeDesc.Type); ilg.Load(enumValue); ilg.Bne(labelFalse); if (isNullable && !element.IsNullable) { source.Load(typeof(object)); ilg.Load(null); ilg.Cne(); } else { ilg.Ldc(true); } ilg.Br(labelEnd); ilg.MarkLabel(labelFalse); ilg.Ldc(false); ilg.MarkLabel(labelEnd); ilg.AndIf(); } labelFalse = ilg.DefineLabel(); labelEnd = ilg.DefineLabel(); MethodInfo XmlNode_get_Name = typeof(XmlNode).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); MethodInfo XmlNode_get_NamespaceURI = typeof(XmlNode).GetMethod( "get_NamespaceURI", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); ilg.Ldloc(elemLoc); ilg.Call(XmlNode_get_Name); ilg.Ldstr(GetCSharpString(element.Name)); MethodInfo String_op_Equality = typeof(string).GetMethod( "op_Equality", CodeGenerator.StaticBindingFlags, new Type[] { typeof(string), typeof(string) } ); ilg.Call(String_op_Equality); ilg.Brfalse(labelFalse); ilg.Ldloc(elemLoc); ilg.Call(XmlNode_get_NamespaceURI); ilg.Ldstr(GetCSharpString(element.Namespace)); ilg.Call(String_op_Equality); ilg.Br(labelEnd); ilg.MarkLabel(labelFalse); ilg.Ldc(false); ilg.MarkLabel(labelEnd); if (choice != null) ilg.If(); else ilg.AndIf(); WriteElement(new SourceInfo("elem", null, null, elemLoc.LocalType, ilg), element, arrayName, writeAccessors); if (choice != null) { ilg.Else(); MethodInfo XmlSerializationWriter_CreateChoiceIdentifierValueException = typeof(XmlSerializationWriter).GetMethod( "CreateChoiceIdentifierValueException", CodeGenerator.InstanceBindingFlags, new Type[] { typeof(String), typeof(String), typeof(String), typeof(String) } ); ilg.Ldarg(0); ilg.Ldstr(GetCSharpString(enumFullName)); ilg.Ldstr(GetCSharpString(choice.MemberName)); ilg.Ldloc(elemLoc); ilg.Call(XmlNode_get_Name); ilg.Ldloc(elemLoc); ilg.Call(XmlNode_get_NamespaceURI); ilg.Call(XmlSerializationWriter_CreateChoiceIdentifierValueException); ilg.Throw(); ilg.EndIf(); } } if (c > 0) { ilg.Else(); } if (unnamedAny != null) { WriteElement(new SourceInfo("elem", null, null, elemLoc.LocalType, ilg), unnamedAny, arrayName, writeAccessors); } else { MethodInfo XmlSerializationWriter_CreateUnknownAnyElementException = typeof(XmlSerializationWriter).GetMethod( "CreateUnknownAnyElementException", CodeGenerator.InstanceBindingFlags, new Type[] { typeof(String), typeof(String) } ); ilg.Ldarg(0); ilg.Ldloc(elemLoc); MethodInfo XmlNode_get_Name = typeof(XmlNode).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); MethodInfo XmlNode_get_NamespaceURI = typeof(XmlNode).GetMethod( "get_NamespaceURI", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); ilg.Call(XmlNode_get_Name); ilg.Ldloc(elemLoc); ilg.Call(XmlNode_get_NamespaceURI); ilg.Call(XmlSerializationWriter_CreateUnknownAnyElementException); ilg.Throw(); } if (c > 0) { ilg.EndIf(); } } if (text != null) { string fullTypeName = text.Mapping.TypeDesc.CSharpName; if (elements.Length > 0) { ilg.InitElseIf(); WriteInstanceOf(source, text.Mapping.TypeDesc.Type); ilg.AndIf(); SourceInfo castedSource = source.CastTo(text.Mapping.TypeDesc); WriteText(castedSource, text); } else { SourceInfo castedSource = source.CastTo(text.Mapping.TypeDesc); WriteText(castedSource, text); } } if (elements.Length > 0) { if (isNullable) { ilg.InitElseIf(); source.Load(null); ilg.Load(null); ilg.AndIf(Cmp.NotEqualTo); } else { ilg.Else(); } MethodInfo XmlSerializationWriter_CreateUnknownTypeException = typeof(XmlSerializationWriter).GetMethod( "CreateUnknownTypeException", CodeGenerator.InstanceBindingFlags, new Type[] { typeof(Object) }); ilg.Ldarg(0); source.Load(typeof(object)); ilg.Call(XmlSerializationWriter_CreateUnknownTypeException); ilg.Throw(); ilg.EndIf(); } // See ilg.If() cond above if (doEndIf) // if (isNullable && choice == null) ilg.EndIf(); } }
private void WriteElement(SourceInfo source, ElementAccessor element, string arrayName, bool writeAccessor) { string name = writeAccessor ? element.Name : element.Mapping.TypeName; string ns = element.Any && element.Name.Length == 0 ? null : (element.Form == XmlSchemaForm.Qualified ? (writeAccessor ? element.Namespace : element.Mapping.Namespace) : ""); if (element.Mapping is NullableMapping) { if (source.Type == element.Mapping.TypeDesc.Type) { MethodInfo Nullable_get_HasValue = element.Mapping.TypeDesc.Type.GetMethod( "get_HasValue", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); source.LoadAddress(element.Mapping.TypeDesc.Type); ilg.Call(Nullable_get_HasValue); } else { source.Load(null); ilg.Load(null); ilg.Cne(); } ilg.If(); string fullTypeName = element.Mapping.TypeDesc.BaseTypeDesc.CSharpName; SourceInfo castedSource = source.CastTo(element.Mapping.TypeDesc.BaseTypeDesc); ElementAccessor e = element.Clone(); e.Mapping = ((NullableMapping)element.Mapping).BaseMapping; WriteElement(e.Any ? source : castedSource, e, arrayName, writeAccessor); if (element.IsNullable) { ilg.Else(); WriteLiteralNullTag(element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""); } ilg.EndIf(); } else if (element.Mapping is ArrayMapping) { ArrayMapping mapping = (ArrayMapping)element.Mapping; if (element.IsUnbounded) { throw Globals.NotSupported("Unreachable: IsUnbounded is never set true!"); } else { ilg.EnterScope(); string fullTypeName = mapping.TypeDesc.CSharpName; WriteArrayLocalDecl(fullTypeName, arrayName, source, mapping.TypeDesc); if (element.IsNullable) { WriteNullCheckBegin(arrayName, element); } else { if (mapping.TypeDesc.IsNullable) { ilg.Ldloc(ilg.GetLocal(arrayName)); ilg.Load(null); ilg.If(Cmp.NotEqualTo); } } WriteStartElement(name, ns, false); WriteArrayItems(mapping.ElementsSortedByDerivation, null, null, mapping.TypeDesc, arrayName, null); WriteEndElement(); if (element.IsNullable) { ilg.EndIf(); } else { if (mapping.TypeDesc.IsNullable) { ilg.EndIf(); } } ilg.ExitScope(); } } else if (element.Mapping is EnumMapping) { WritePrimitive("WriteElementString", name, ns, element.Default, source, element.Mapping, false, true, element.IsNullable); } else if (element.Mapping is PrimitiveMapping) { PrimitiveMapping mapping = (PrimitiveMapping)element.Mapping; if (mapping.TypeDesc == QnameTypeDesc) WriteQualifiedNameElement(name, ns, element.Default, source, element.IsNullable, mapping); else { string suffixRaw = mapping.TypeDesc.XmlEncodingNotRequired ? "Raw" : ""; WritePrimitive(element.IsNullable ? ("WriteNullableStringLiteral" + suffixRaw) : ("WriteElementString" + suffixRaw), name, ns, element.Default, source, mapping, false, true, element.IsNullable); } } else if (element.Mapping is StructMapping) { StructMapping mapping = (StructMapping)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(SR.Format(SR.XmlInternalErrorMethod, mapping.TypeDesc.Name)); #endif List<Type> argTypes = new List<Type>(); ilg.Ldarg(0); ilg.Ldstr(GetCSharpString(name)); argTypes.Add(typeof(string)); ilg.Ldstr(GetCSharpString(ns)); argTypes.Add(typeof(string)); source.Load(mapping.TypeDesc.Type); argTypes.Add(mapping.TypeDesc.Type); if (mapping.TypeDesc.IsNullable) { ilg.Ldc(element.IsNullable); argTypes.Add(typeof(Boolean)); } ilg.Ldc(false); argTypes.Add(typeof(Boolean)); MethodBuilder methodBuilder = EnsureMethodBuilder(typeBuilder, methodName, CodeGenerator.PrivateMethodAttributes, typeof(void), argTypes.ToArray()); ilg.Call(methodBuilder); } else if (element.Mapping is SpecialMapping) { SpecialMapping mapping = (SpecialMapping)element.Mapping; TypeDesc td = mapping.TypeDesc; string fullTypeName = td.CSharpName; if (element.Mapping is SerializableMapping) { WriteElementCall("WriteSerializable", typeof(IXmlSerializable), source, name, ns, element.IsNullable, !element.Any); } else { // XmlNode, XmlElement Label ifLabel1 = ilg.DefineLabel(); Label ifLabel2 = ilg.DefineLabel(); source.Load(null); ilg.IsInst(typeof(XmlNode)); ilg.Brtrue(ifLabel1); source.Load(null); ilg.Load(null); ilg.Ceq(); ilg.Br(ifLabel2); ilg.MarkLabel(ifLabel1); ilg.Ldc(true); ilg.MarkLabel(ifLabel2); ilg.If(); WriteElementCall("WriteElementLiteral", typeof(XmlNode), source, name, ns, element.IsNullable, element.Any); ilg.Else(); MethodInfo XmlSerializationWriter_CreateInvalidAnyTypeException = typeof(XmlSerializationWriter).GetMethod( "CreateInvalidAnyTypeException", CodeGenerator.InstanceBindingFlags, new Type[] { typeof(Object) } ); ilg.Ldarg(0); source.Load(null); ilg.Call(XmlSerializationWriter_CreateInvalidAnyTypeException); ilg.Throw(); ilg.EndIf(); } } else { throw new InvalidOperationException(SR.XmlInternalError); } }
private void WriteAttribute(SourceInfo source, AttributeAccessor attribute, string parent) { if (attribute.Mapping is SpecialMapping) { SpecialMapping special = (SpecialMapping)attribute.Mapping; if (special.TypeDesc.Kind == TypeKind.Attribute || special.TypeDesc.CanBeAttributeValue) { System.Diagnostics.Debug.Assert(parent == "o" || parent == "p"); MethodInfo XmlSerializationWriter_WriteXmlAttribute = typeof(XmlSerializationWriter).GetMethod( "WriteXmlAttribute", CodeGenerator.InstanceBindingFlags, new Type[] { typeof(XmlNode), typeof(Object) } ); ilg.Ldarg(0); ilg.Ldloc(source.Source); ilg.Ldarg(parent); ilg.ConvertValue(ilg.GetArg(parent).ArgType, typeof(Object)); ilg.Call(XmlSerializationWriter_WriteXmlAttribute); } else throw new InvalidOperationException(SR.XmlInternalError); } else { TypeDesc typeDesc = attribute.Mapping.TypeDesc; source = source.CastTo(typeDesc); WritePrimitive("WriteAttribute", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "", attribute.Default, source, attribute.Mapping, false, false, false); } }