diff options
author | Shin Mao <shmao@microsoft.com> | 2018-01-08 22:47:43 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-08 22:47:43 +0300 |
commit | b032565f4c8186dcb82a0d6be8a94e660184405a (patch) | |
tree | 1011db98a51777c8d2d08c66002797896cfb2698 /src/System.Private.Xml | |
parent | d576779bbef481e71c97572e5d033ca9f1bdb4c7 (diff) |
Move XmlSerializer CodeGen from SGen to S.P.Xml (#26169)
* Move XmlSerializer CodeGen from SGen to S.P.Xml (#24401)
* Move XmlSerializer CodeGen from SGen to S.P.Xml
The PR is moving the CodeGen code of XmlSerializer from SGen back to
System.Private.Xml.
* One minor change.
* Error handling.
* Add PreGenOnly Check for FromMappings.
* Fix the sgen generated code error for a type with mismatched attribute and property. (#24671)
* Removed XMLSERIALIZERGENERATOR entries.
Diffstat (limited to 'src/System.Private.Xml')
44 files changed, 5719 insertions, 392 deletions
diff --git a/src/System.Private.Xml/src/Resources/Strings.resx b/src/System.Private.Xml/src/Resources/Strings.resx index c3943b26f7..b7c8d8724f 100644 --- a/src/System.Private.Xml/src/Resources/Strings.resx +++ b/src/System.Private.Xml/src/Resources/Strings.resx @@ -3448,4 +3448,7 @@ Usage: dotnet {0} [[/assembly:<assembly name>] | [<assembly file locati <data name="MoreHelp" xml:space="preserve"> <value>If you would like more help, please type "sgen {0}".</value> </data> + <data name="GenerateSerializerNotFound" xml:space="preserve"> + <value>`System.Xml.Serialization.XmlSerializer` does not have a method named `GenerateSerializerNotFound`. SGen does not support the framework of the version you are using.</value> + </data> </root>
\ No newline at end of file diff --git a/src/System.Private.Xml/src/System.Private.Xml.csproj b/src/System.Private.Xml/src/System.Private.Xml.csproj index fa2aa25278..85a2c5ba78 100644 --- a/src/System.Private.Xml/src/System.Private.Xml.csproj +++ b/src/System.Private.Xml/src/System.Private.Xml.csproj @@ -20,9 +20,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Release|AnyCPU'" /> <ItemGroup> - <Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs"> - <Link>System\StringBuilderCache.cs</Link> - </Compile> + <Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs" /> <Compile Include="System\Xml\BinaryXml\XmlBinaryReader.cs" /> <Compile Include="System\Xml\BinaryXml\BinXmlToken.cs" /> <Compile Include="System\Xml\BinaryXml\SqlUtils.cs" /> @@ -755,4 +753,4 @@ <Compile Include="System\Xml\Core\XmlTextReaderImpl.Unix.cs" /> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/System.Private.Xml/src/System/Xml/BinHexDecoder.cs b/src/System.Private.Xml/src/System/Xml/BinHexDecoder.cs index b4fbe7ba0d..169c7fad63 100644 --- a/src/System.Private.Xml/src/System/Xml/BinHexDecoder.cs +++ b/src/System.Private.Xml/src/System/Xml/BinHexDecoder.cs @@ -7,17 +7,6 @@ using System.Diagnostics; namespace System.Xml { -#if XMLSERIALIZERGENERATOR - internal abstract class IncrementalReadDecoder - { - internal abstract int DecodedCount { get; } - internal abstract bool IsFull { get; } - internal abstract void SetNextOutputBuffer(Array array, int offset, int len); - internal abstract int Decode(char[] chars, int startPos, int len); - internal abstract int Decode(string str, int startPos, int len); - internal abstract void Reset(); - } -#endif internal class BinHexDecoder : IncrementalReadDecoder { // @@ -172,11 +161,7 @@ namespace System.Xml if (hasHalfByteCached && !allowOddChars) { -#if XMLSERIALIZERGENERATOR - throw new XmlException(SR.Format(SR.Xml_InvalidBinHexValueOddCount, new string(chars))); -#else throw new XmlException(SR.Xml_InvalidBinHexValueOddCount, new string(chars)); -#endif } if (bytesDecoded < bytes.Length) @@ -229,11 +214,7 @@ namespace System.Xml } else { -#if XMLSERIALIZERGENERATOR - throw new XmlException(SR.Format(SR.Xml_InvalidBinHexValue, new string(pChars, 0, (int)(pCharsEndPos - pChars)))); -#else throw new XmlException(SR.Xml_InvalidBinHexValue, new string(pChars, 0, (int)(pCharsEndPos - pChars))); -#endif } if (hasHalfByteCached) diff --git a/src/System.Private.Xml/src/System/Xml/Extensions/ExtensionMethods.cs b/src/System.Private.Xml/src/System/Xml/Extensions/ExtensionMethods.cs index 1ffa891c21..9f968d634f 100644 --- a/src/System.Private.Xml/src/System/Xml/Extensions/ExtensionMethods.cs +++ b/src/System.Private.Xml/src/System/Xml/Extensions/ExtensionMethods.cs @@ -48,25 +48,6 @@ namespace System.Xml.Extensions return type.GetMethod(methodName, bindingFlags, null, parameterTypes, null); } -#if XMLSERIALIZERGENERATOR - internal static string ToBinHexString(byte[] inArray) - { - if (inArray == null) - { - throw new ArgumentNullException(nameof(inArray)); - } - return BinHexEncoder.Encode(inArray, 0, inArray.Length); - } - - internal static byte[] FromBinHexString(string s, bool allowOddCount) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - return BinHexDecoder.Decode(s.ToCharArray(), allowOddCount); - } -#endif #endregion internal static Uri ToUri(string s) diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerationoptions.cs b/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerationoptions.cs index ad75d457e4..fc25ba02f4 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerationoptions.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerationoptions.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.ComponentModel; @@ -17,11 +13,7 @@ namespace System.Xml.Serialization /// Specifies various flavours of XmlCodeExporter generated code. /// </devdoc> [Flags] -#if XMLSERIALIZERGENERATOR - internal enum CodeGenerationOptions -#else public enum CodeGenerationOptions -#endif { /// <include file='doc\CodeGenerationOptions.uex' path='docs/doc[@for="CodeGenerationOptions.None"]/*' /> /// <devdoc> diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs b/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs index 0605e6b52f..77a75dc56e 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs @@ -8,11 +8,7 @@ using System.Resources; using System.Runtime.CompilerServices; #if !FEATURE_SERIALIZATION_UAPAOT -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Collections; @@ -1675,4 +1671,4 @@ namespace System.Xml.Serialization } } } -#endif
\ No newline at end of file +#endif diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs b/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs index 943a0e9ae0..24b8a8c889 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs @@ -10,21 +10,13 @@ using System.Globalization; using System.Diagnostics; using System.Reflection; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { ///<internalonly/> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class CodeIdentifier -#else public class CodeIdentifier -#endif { internal const int MaxIdentifierLength = 511; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifiers.cs b/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifiers.cs index a95a0b492c..eefbccdedb 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifiers.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifiers.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Collections; @@ -38,11 +34,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class CodeIdentifiers -#else public class CodeIdentifiers -#endif { private Hashtable _identifiers; private Hashtable _reservedIdentifiers; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Compilation.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Compilation.cs index 45d035d179..99b53934da 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Compilation.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Compilation.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Configuration; using System.Reflection; @@ -77,7 +73,6 @@ namespace System.Xml.Serialization if (!containsSoapMapping && !TempAssembly.UseLegacySerializerGeneration) { -#if !XMLSERIALIZERGENERATOR try { _assembly = GenerateRefEmitAssembly(xmlMappings, types, defaultNamespace); @@ -89,7 +84,6 @@ namespace System.Xml.Serialization } // Add other known exceptions here... // -#endif } else { @@ -104,7 +98,8 @@ namespace System.Xml.Serialization #if DEBUG // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe - if (_assembly == null) throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, "Failed to generate XmlSerializer assembly, but did not throw")); + if (_assembly == null) + throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, "Failed to generate XmlSerializer assembly, but did not throw")); #endif InitAssemblyMethods(xmlMappings); } @@ -197,6 +192,11 @@ namespace System.Xml.Serialization } if (serializer == null) { + if (XmlSerializer.Mode == SerializationMode.PreGenOnly) + { + throw new Exception(SR.Format(SR.FailLoadAssemblyUnderPregenMode, serializerName)); + } + return null; } } @@ -237,7 +237,7 @@ namespace System.Xml.Serialization return null; } -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT private static string GenerateAssemblyId(Type type) { Module[] modules = type.Assembly.GetModules(); @@ -406,9 +406,6 @@ namespace System.Xml.Serialization } } -#endif -#if !XMLSERIALIZERGENERATOR -#if !FEATURE_SERIALIZATION_UAPAOT [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "It is safe because the serialization assembly is generated by the framework code, not by the user.")] internal static Assembly GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types, string defaultNamespace) { @@ -487,7 +484,6 @@ namespace System.Xml.Serialization return writerType.Assembly; } #endif -#endif private static MethodInfo GetMethodFromType(Type type, string methodName) { @@ -504,7 +500,8 @@ namespace System.Xml.Serialization { typeName = GeneratedAssemblyNamespace + "." + typeName; Type type = assembly.GetType(typeName); - if (type == null) throw new InvalidOperationException(SR.Format(SR.XmlMissingType, typeName, assembly.FullName)); + if (type == null) + throw new InvalidOperationException(SR.Format(SR.XmlMissingType, typeName, assembly.FullName)); return type; } @@ -634,7 +631,8 @@ namespace System.Xml.Serialization public override bool Equals(object o) { TempAssemblyCacheKey key = o as TempAssemblyCacheKey; - if (key == null) return false; + if (key == null) + return false; return (key._type == _type && key._ns == _ns); } @@ -664,11 +662,18 @@ namespace System.Xml.Serialization lock (this) { TempAssembly tempAssembly; - if (_cache.TryGetValue(key, out tempAssembly) && tempAssembly == assembly) return; + if (_cache.TryGetValue(key, out tempAssembly) && tempAssembly == assembly) + return; _cache = new Dictionary<TempAssemblyCacheKey, TempAssembly>(_cache); // clone _cache[key] = assembly; } } } + + internal static class ThisAssembly + { + internal const string Version = "1.0.0.0"; + internal const string InformationalVersion = "1.0.0.0"; + } } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs index b4ce90598d..2ba30b7dc0 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System.Reflection.Emit; @@ -27,12 +23,10 @@ namespace System.Xml.Serialization internal class Compiler { -#if !XMLSERIALIZERGENERATOR private bool _debugEnabled = DiagnosticsSwitches.KeepTempFiles.Enabled; -#endif private StringWriter _writer = new StringWriter(CultureInfo.InvariantCulture); -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT // SxS: This method does not take any resource name and does not expose any resources to the caller. // It's OK to suppress the SxS warning. internal void AddImport(Type type, Hashtable types) diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Globals.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Globals.cs index b3891a2f15..caaadb7e5c 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Globals.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Globals.cs @@ -8,11 +8,7 @@ using System.Reflection; using System; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { internal static class Globals { diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/IXmlTextParser.cs b/src/System.Private.Xml/src/System/Xml/Serialization/IXmlTextParser.cs index 1a317459e0..fedf5bc9b9 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/IXmlTextParser.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/IXmlTextParser.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Xml; @@ -15,11 +11,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>This class is <see langword='interface'/> .</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal interface IXmlTextParser -#else public interface IXmlTextParser -#endif { /// <include file='doc\IXmlTextParser.uex' path='docs/doc[@for="IXmlTextParser.Normalized"]/*' /> /// <internalonly/> diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Mappings.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Mappings.cs index 057f40be3b..bdc35deb2f 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Mappings.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Mappings.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System.Collections; @@ -1247,10 +1243,8 @@ namespace System.Xml.Serialization XmlSchemaObjectTable elements = null; if (Schema != null && Schema.TargetNamespace == elementNs) { -#if !XMLSERIALIZERGENERATOR XmlSchemas.Preprocess(Schema); elements = Schema.Elements; -#endif } else if (Schemas != null) { @@ -1337,7 +1331,7 @@ namespace System.Xml.Serialization // make sure that user-specified schemas are valid _schemas.ValidationEventHandler += new ValidationEventHandler(ValidationCallbackWithErrorCode); _schemas.Compile(); -#if !XMLSERIALIZERGENERATOR + // at this point we verified that the information returned by the IXmlSerializable is valid // Now check to see if the type was referenced before: // UNDONE check for the duplcate types @@ -1369,7 +1363,6 @@ namespace System.Xml.Serialization _xsdType = _xsdType.Redefined != null ? _xsdType.Redefined : _xsdType; } } -#endif } else { diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Models.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Models.cs index d5bb2211a1..26735266ea 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Models.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Models.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Reflection; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/NameTable.cs b/src/System.Private.Xml/src/System/Xml/Serialization/NameTable.cs index a07d4dc2b7..65e907ae5a 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/NameTable.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/NameTable.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Xml; using System; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/PrimitiveXmlSerializers.cs b/src/System.Private.Xml/src/System/Xml/Serialization/PrimitiveXmlSerializers.cs index 5da34c0437..8ab90c2f82 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/PrimitiveXmlSerializers.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/PrimitiveXmlSerializers.cs @@ -4,15 +4,9 @@ using System; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -{ - internal class XmlSerializationPrimitiveWriter : Microsoft.XmlSerializer.Generator.XmlSerializationWriter -#else namespace System.Xml.Serialization { internal class XmlSerializationPrimitiveWriter : System.Xml.Serialization.XmlSerializationWriter -#endif { internal void Write_string(object o) { @@ -236,7 +230,6 @@ namespace System.Xml.Serialization } } -#if !XMLSERIALIZERGENERATOR internal class XmlSerializationPrimitiveReader : System.Xml.Serialization.XmlSerializationReader { internal object Read_string() @@ -759,5 +752,4 @@ namespace System.Xml.Serialization _id1_QName = Reader.NameTable.Add(@"QName"); } } -#endif } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs b/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs index 4b14059242..88fc758431 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs @@ -19,11 +19,7 @@ using System.Xml.Serialization; using System.Linq.Expressions; using System.Collections.Concurrent; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { internal delegate void UnknownNodeAction(object o); diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs index a19d017d6d..86377e0a2a 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs @@ -13,11 +13,7 @@ using System.Threading.Tasks; using System.Xml.Schema; using System.Xml; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { internal class ReflectionXmlSerializationWriter : XmlSerializationWriter { diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs index f1bd443a62..05838f6828 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System; @@ -23,11 +19,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class SoapReflectionImporter -#else public class SoapReflectionImporter -#endif { private TypeScope _typeScope; private SoapAttributeOverrides _attributeOverrides; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/SoapSchemamember.cs b/src/System.Private.Xml/src/System/Xml/Serialization/SoapSchemamember.cs index 1f056c0d5a..7840b9eb05 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/SoapSchemamember.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/SoapSchemamember.cs @@ -2,22 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Xml; /// <include file='doc\SoapSchemaMember.uex' path='docs/doc[@for="SoapSchemaMember"]/*' /> /// <internalonly/> -#if XMLSERIALIZERGENERATOR - internal class SoapSchemaMember -#else public class SoapSchemaMember -#endif { private string _memberName; private XmlQualifiedName _type = XmlQualifiedName.Empty; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs b/src/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs index bedf52a1c5..77059f1316 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs @@ -11,11 +11,7 @@ using System.Text.RegularExpressions; using System.Xml.Extensions; #if !FEATURE_SERIALIZATION_UAPAOT -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { internal class SourceInfo { @@ -267,4 +263,4 @@ namespace System.Xml.Serialization } } } -#endif
\ No newline at end of file +#endif diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/TypeCode.cs b/src/System.Private.Xml/src/System/Xml/Serialization/TypeCode.cs index 45be3c59bf..f55392df09 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/TypeCode.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/TypeCode.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/TypeExtensions.cs b/src/System.Private.Xml/src/System/Xml/Serialization/TypeExtensions.cs index 5e98bdd677..7bee06dc2b 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/TypeExtensions.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/TypeExtensions.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Reflection; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs index 5d0e51d811..079ec5e661 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.IO; @@ -736,7 +732,7 @@ namespace System.Xml.Serialization return typeDesc; } -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT internal TypeMapping GetTypeMappingFromTypeDesc(TypeDesc typeDesc) { foreach (TypeMapping typeMapping in TypeMappings) @@ -1392,7 +1388,6 @@ namespace System.Xml.Serialization name = type.Substring(nsLen + 1, nameLen - nsLen - 1); dims = type.Substring(nameLen); -#if !XMLSERIALIZERGENERATOR // parent is not null only in the case when we used XmlSchema.Read(), // in which case we need to fixup the wsdl:arayType attribute value while (parent != null) @@ -1409,7 +1404,6 @@ namespace System.Xml.Serialization parent = parent.Parent; } -#endif return new XmlQualifiedName(name, ns); } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributeOverrides.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributeOverrides.cs index d24e2666ae..2c0465d99b 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributeOverrides.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributeOverrides.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System.Collections; @@ -19,11 +15,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlAttributeOverrides -#else public class XmlAttributeOverrides -#endif { private readonly Dictionary<Type, Dictionary<string, XmlAttributes>> _types = new Dictionary<Type, Dictionary<string, XmlAttributes>>(); diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs index eea7dd42b7..e5885dcaef 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Reflection; @@ -35,11 +31,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlAttributes -#else public class XmlAttributes -#endif { private XmlElementAttributes _xmlElements = new XmlElementAttributes(); private XmlArrayItemAttributes _xmlArrayItems = new XmlArrayItemAttributes(); diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlCountingReader.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlCountingReader.cs index 248947dd5e..8c9d08ff67 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlCountingReader.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlCountingReader.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.IO; using System.Collections; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlMapping.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlMapping.cs index f44af553e5..1e77cef8f3 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlMapping.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlMapping.cs @@ -9,18 +9,10 @@ using System.Reflection; using System.Xml.Serialization; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { [Flags] -#if XMLSERIALIZERGENERATOR - internal enum XmlMappingAccess -#else public enum XmlMappingAccess -#endif { None = 0x00, Read = 0x01, @@ -31,11 +23,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal abstract class XmlMapping -#else public abstract class XmlMapping -#endif { private TypeScope _scope; private bool _generateSerializer = false; @@ -72,11 +60,7 @@ namespace System.Xml.Serialization /// </devdoc> public string ElementName { -#if XMLSERIALIZERGENERATOR - get { return Microsoft.XmlSerializer.Generator.Accessor.UnescapeName(Accessor.Name); } -#else get { return System.Xml.Serialization.Accessor.UnescapeName(Accessor.Name); } -#endif } /// <devdoc> diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlMemberMapping.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlMemberMapping.cs index 44cfa83562..6b06c25a60 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlMemberMapping.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlMemberMapping.cs @@ -6,18 +6,10 @@ using System.Reflection; using System; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { /// <internalonly/> -#if XMLSERIALIZERGENERATOR - internal class XmlMemberMapping -#else public class XmlMemberMapping -#endif { private MemberMapping _mapping; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlMembersMapping.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlMembersMapping.cs index 5578e133f5..d9ba799d2d 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlMembersMapping.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlMembersMapping.cs @@ -7,21 +7,13 @@ using System; using System.Text; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { ///<internalonly/> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlMembersMapping : XmlMapping -#else public class XmlMembersMapping : XmlMapping -#endif { private XmlMemberMapping[] _mappings; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionImporter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionImporter.cs index d131f471f5..94bbcefb24 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionImporter.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionImporter.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System; @@ -26,11 +22,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlReflectionImporter -#else public class XmlReflectionImporter -#endif { private TypeScope _typeScope; private XmlAttributeOverrides _attributeOverrides; @@ -41,9 +33,7 @@ namespace System.Xml.Serialization private NameTable _xsdAttributes; // xmlattributetname + xmlns -> AttributeAccessor private Hashtable _specials; // type -> SpecialMapping private Hashtable _anonymous = new Hashtable(); // type -> AnonymousMapping -#if !XMLSERIALIZERGENERATOR private NameTable _serializables; // type name --> new SerializableMapping -#endif private StructMapping _root; private string _defaultNs; private ModelScope _modelScope; @@ -522,7 +512,6 @@ namespace System.Xml.Serialization XmlQualifiedName qname = serializableMapping.XsiType; if (qname != null && !qname.IsEmpty) { -#if !XMLSERIALIZERGENERATOR if (_serializables == null) _serializables = new NameTable(); SerializableMapping existingMapping = (SerializableMapping)_serializables[qname]; @@ -547,7 +536,6 @@ namespace System.Xml.Serialization _serializables[qname] = serializableMapping; } -#endif serializableMapping.TypeName = qname.Name; serializableMapping.Namespace = qname.Namespace; } @@ -575,7 +563,6 @@ namespace System.Xml.Serialization return mapping; } -#if !XMLSERIALIZERGENERATOR internal void SetBase(SerializableMapping mapping, XmlQualifiedName baseQname) { if (baseQname.IsEmpty) return; @@ -604,7 +591,6 @@ namespace System.Xml.Serialization } mapping.SetBaseMapping((SerializableMapping)_serializables[baseQname]); } -#endif private static string GetContextName(ImportContext context) { @@ -2340,11 +2326,7 @@ namespace System.Xml.Serialization internal RecursionLimiter() { _depth = 0; -#if XMLSERIALIZERGENERATOR - _maxDepth = int.MaxValue; -#else _maxDepth = DiagnosticsSwitches.NonRecursiveTypeLoading.Enabled ? 1 : int.MaxValue; -#endif } internal bool IsExceededLimit { get { return _depth > _maxDepth; } } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionMember.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionMember.cs index 2ef1c0373e..8d59d700ff 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionMember.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlReflectionMember.cs @@ -6,21 +6,13 @@ using System; using System.Xml.Serialization; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { ///<internalonly/> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlReflectionMember -#else public class XmlReflectionMember -#endif { private string _memberName; private Type _type; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationGeneratedCode.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationGeneratedCode.cs index caabe4b045..8a453d4642 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationGeneratedCode.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationGeneratedCode.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.IO; @@ -18,11 +14,7 @@ namespace System.Xml.Serialization using System.Globalization; ///<internalonly/> -#if XMLSERIALIZERGENERATOR - internal abstract class XmlSerializationGeneratedCode -#else public abstract class XmlSerializationGeneratedCode -#endif { internal void Init(TempAssembly tempAssembly) { @@ -33,4 +25,387 @@ namespace System.Xml.Serialization { } } +#if !FEATURE_SERIALIZATION_UAPAOT + internal class XmlSerializationCodeGen + { + private IndentedWriter _writer; + private int _nextMethodNumber = 0; + private Hashtable _methodNames = new Hashtable(); + private ReflectionAwareCodeGen _raCodeGen; + private TypeScope[] _scopes; + private TypeDesc _stringTypeDesc = null; + private TypeDesc _qnameTypeDesc = null; + private string _access; + private string _className; + private TypeMapping[] _referencedMethods; + private int _references = 0; + private Hashtable _generatedMethods = new Hashtable(); + + internal XmlSerializationCodeGen(IndentedWriter writer, TypeScope[] scopes, string access, string className) + { + _writer = writer; + _scopes = scopes; + if (scopes.Length > 0) + { + _stringTypeDesc = scopes[0].GetTypeDesc(typeof(string)); + _qnameTypeDesc = scopes[0].GetTypeDesc(typeof(XmlQualifiedName)); + } + _raCodeGen = new ReflectionAwareCodeGen(writer); + _className = className; + _access = access; + } + + internal IndentedWriter Writer { get { return _writer; } } + internal int NextMethodNumber { get { return _nextMethodNumber; } set { _nextMethodNumber = value; } } + internal ReflectionAwareCodeGen RaCodeGen { get { return _raCodeGen; } } + internal TypeDesc StringTypeDesc { get { return _stringTypeDesc; } } + internal TypeDesc QnameTypeDesc { get { return _qnameTypeDesc; } } + internal string ClassName { get { return _className; } } + internal string Access { get { return _access; } } + internal TypeScope[] Scopes { get { return _scopes; } } + internal Hashtable MethodNames { get { return _methodNames; } } + internal Hashtable GeneratedMethods { get { return _generatedMethods; } } + + internal virtual void GenerateMethod(TypeMapping mapping) { } + + internal void GenerateReferencedMethods() + { + while (_references > 0) + { + TypeMapping mapping = _referencedMethods[--_references]; + GenerateMethod(mapping); + } + } + + internal string ReferenceMapping(TypeMapping mapping) + { + if (!mapping.IsSoap) + { + if (_generatedMethods[mapping] == null) + { + _referencedMethods = EnsureArrayIndex(_referencedMethods, _references); + _referencedMethods[_references++] = mapping; + } + } + return (string)_methodNames[mapping]; + } + + private TypeMapping[] EnsureArrayIndex(TypeMapping[] a, int index) + { + if (a == null) return new TypeMapping[32]; + if (index < a.Length) return a; + TypeMapping[] b = new TypeMapping[a.Length + 32]; + Array.Copy(a, b, index); + return b; + } + + internal void WriteQuotedCSharpString(string value) + { + _raCodeGen.WriteQuotedCSharpString(value); + } + + internal void GenerateHashtableGetBegin(string privateName, string publicName) + { + _writer.Write(typeof(Hashtable).FullName); + _writer.Write(" "); + _writer.Write(privateName); + _writer.WriteLine(" = null;"); + _writer.Write("public override "); + _writer.Write(typeof(Hashtable).FullName); + + _writer.Write(" "); + _writer.Write(publicName); + _writer.WriteLine(" {"); + _writer.Indent++; + + _writer.WriteLine("get {"); + _writer.Indent++; + + _writer.Write("if ("); + _writer.Write(privateName); + _writer.WriteLine(" == null) {"); + _writer.Indent++; + + _writer.Write(typeof(Hashtable).FullName); + _writer.Write(" _tmp = new "); + _writer.Write(typeof(Hashtable).FullName); + _writer.WriteLine("();"); + } + + internal void GenerateHashtableGetEnd(string privateName) + { + _writer.Write("if ("); + _writer.Write(privateName); + _writer.Write(" == null) "); + _writer.Write(privateName); + _writer.WriteLine(" = _tmp;"); + _writer.Indent--; + _writer.WriteLine("}"); + + _writer.Write("return "); + _writer.Write(privateName); + _writer.WriteLine(";"); + _writer.Indent--; + _writer.WriteLine("}"); + + _writer.Indent--; + _writer.WriteLine("}"); + } + internal void GeneratePublicMethods(string privateName, string publicName, string[] methods, XmlMapping[] xmlMappings) + { + GenerateHashtableGetBegin(privateName, publicName); + if (methods != null && methods.Length != 0 && xmlMappings != null && xmlMappings.Length == methods.Length) + { + for (int i = 0; i < methods.Length; i++) + { + if (methods[i] == null) + continue; + _writer.Write("_tmp["); + WriteQuotedCSharpString(xmlMappings[i].Key); + _writer.Write("] = "); + WriteQuotedCSharpString(methods[i]); + _writer.WriteLine(";"); + } + } + GenerateHashtableGetEnd(privateName); + } + + internal void GenerateSupportedTypes(Type[] types) + { + _writer.Write("public override "); + _writer.Write(typeof(bool).FullName); + _writer.Write(" CanSerialize("); + _writer.Write(typeof(Type).FullName); + _writer.WriteLine(" type) {"); + _writer.Indent++; + Hashtable uniqueTypes = new Hashtable(); + for (int i = 0; i < types.Length; i++) + { + Type type = types[i]; + + if (type == null) + continue; + if (!type.IsPublic && !type.IsNestedPublic) + continue; + if (uniqueTypes[type] != null) + continue; + if (DynamicAssemblies.IsTypeDynamic(type)) + continue; + if (type.IsGenericType || type.ContainsGenericParameters && DynamicAssemblies.IsTypeDynamic(type.GetGenericArguments())) + continue; + uniqueTypes[type] = type; + _writer.Write("if (type == typeof("); + _writer.Write(CodeIdentifier.GetCSharpName(type)); + _writer.WriteLine(")) return true;"); + } + _writer.WriteLine("return false;"); + _writer.Indent--; + _writer.WriteLine("}"); + } + + internal string GenerateBaseSerializer(string baseSerializer, string readerClass, string writerClass, CodeIdentifiers classes) + { + baseSerializer = CodeIdentifier.MakeValid(baseSerializer); + baseSerializer = classes.AddUnique(baseSerializer, baseSerializer); + + _writer.WriteLine(); + _writer.Write("public abstract class "); + _writer.Write(CodeIdentifier.GetCSharpName(baseSerializer)); + _writer.Write(" : "); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializer).FullName); + _writer.WriteLine(" {"); + _writer.Indent++; + + _writer.Write("protected override "); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializationReader).FullName); + _writer.WriteLine(" CreateReader() {"); + _writer.Indent++; + _writer.Write("return new "); + _writer.Write(readerClass); + _writer.WriteLine("();"); + _writer.Indent--; + _writer.WriteLine("}"); + + _writer.Write("protected override "); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializationWriter).FullName); + _writer.WriteLine(" CreateWriter() {"); + _writer.Indent++; + _writer.Write("return new "); + _writer.Write(writerClass); + _writer.WriteLine("();"); + _writer.Indent--; + _writer.WriteLine("}"); + + _writer.Indent--; + _writer.WriteLine("}"); + + return baseSerializer; + } + + internal string GenerateTypedSerializer(string readMethod, string writeMethod, XmlMapping mapping, CodeIdentifiers classes, string baseSerializer, string readerClass, string writerClass) + { + string serializerName = CodeIdentifier.MakeValid(Accessor.UnescapeName(mapping.Accessor.Mapping.TypeDesc.Name)); + serializerName = classes.AddUnique(serializerName + "Serializer", mapping); + + _writer.WriteLine(); + _writer.Write("public sealed class "); + _writer.Write(CodeIdentifier.GetCSharpName(serializerName)); + _writer.Write(" : "); + _writer.Write(baseSerializer); + _writer.WriteLine(" {"); + _writer.Indent++; + + _writer.WriteLine(); + _writer.Write("public override "); + _writer.Write(typeof(bool).FullName); + _writer.Write(" CanDeserialize("); + _writer.Write(typeof(XmlReader).FullName); + _writer.WriteLine(" xmlReader) {"); + _writer.Indent++; + + if (mapping.Accessor.Any) + { + _writer.WriteLine("return true;"); + } + else + { + _writer.Write("return xmlReader.IsStartElement("); + WriteQuotedCSharpString(mapping.Accessor.Name); + _writer.Write(", "); + WriteQuotedCSharpString(mapping.Accessor.Namespace); + _writer.WriteLine(");"); + } + _writer.Indent--; + _writer.WriteLine("}"); + + if (writeMethod != null) + { + _writer.WriteLine(); + _writer.Write("protected override void Serialize(object objectToSerialize, "); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializationWriter).FullName); + _writer.WriteLine(" writer) {"); + _writer.Indent++; + _writer.Write("(("); + _writer.Write(writerClass); + _writer.Write(")writer)."); + _writer.Write(writeMethod); + _writer.Write("("); + if (mapping is XmlMembersMapping) + { + _writer.Write("(object[])"); + } + _writer.WriteLine("objectToSerialize);"); + _writer.Indent--; + _writer.WriteLine("}"); + } + if (readMethod != null) + { + _writer.WriteLine(); + _writer.Write("protected override object Deserialize("); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializationReader).FullName); + _writer.WriteLine(" reader) {"); + _writer.Indent++; + _writer.Write("return (("); + _writer.Write(readerClass); + _writer.Write(")reader)."); + _writer.Write(readMethod); + _writer.WriteLine("();"); + _writer.Indent--; + _writer.WriteLine("}"); + } + _writer.Indent--; + _writer.WriteLine("}"); + + return serializerName; + } + + private void GenerateTypedSerializers(Hashtable serializers) + { + string privateName = "typedSerializers"; + GenerateHashtableGetBegin(privateName, "TypedSerializers"); + + foreach (string key in serializers.Keys) + { + _writer.Write("_tmp.Add("); + WriteQuotedCSharpString(key); + _writer.Write(", new "); + _writer.Write((string)serializers[key]); + _writer.WriteLine("());"); + } + GenerateHashtableGetEnd("typedSerializers"); + } + + //GenerateGetSerializer(serializers, xmlMappings); + private void GenerateGetSerializer(Hashtable serializers, XmlMapping[] xmlMappings) + { + _writer.Write("public override "); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializer).FullName); + _writer.Write(" GetSerializer("); + _writer.Write(typeof(Type).FullName); + _writer.WriteLine(" type) {"); + _writer.Indent++; + + for (int i = 0; i < xmlMappings.Length; i++) + { + if (xmlMappings[i] is XmlTypeMapping) + { + Type type = xmlMappings[i].Accessor.Mapping.TypeDesc.Type; + if (type == null) + continue; + if (!type.IsPublic && !type.IsNestedPublic) + continue; + if (DynamicAssemblies.IsTypeDynamic(type)) + continue; + if (type.IsGenericType || type.ContainsGenericParameters && DynamicAssemblies.IsTypeDynamic(type.GetGenericArguments())) + continue; + _writer.Write("if (type == typeof("); + _writer.Write(CodeIdentifier.GetCSharpName(type)); + _writer.Write(")) return new "); + _writer.Write((string)serializers[xmlMappings[i].Key]); + _writer.WriteLine("();"); + } + } + _writer.WriteLine("return null;"); + _writer.Indent--; + _writer.WriteLine("}"); + } + + internal void GenerateSerializerContract(string className, XmlMapping[] xmlMappings, Type[] types, string readerType, string[] readMethods, string writerType, string[] writerMethods, Hashtable serializers) + { + _writer.WriteLine(); + _writer.Write("public class XmlSerializerContract : global::"); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializerImplementation).FullName); + _writer.WriteLine(" {"); + _writer.Indent++; + + _writer.Write("public override global::"); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializationReader).FullName); + _writer.Write(" Reader { get { return new "); + _writer.Write(readerType); + _writer.WriteLine("(); } }"); + + _writer.Write("public override global::"); + _writer.Write(typeof(System.Xml.Serialization.XmlSerializationWriter).FullName); + _writer.Write(" Writer { get { return new "); + _writer.Write(writerType); + _writer.WriteLine("(); } }"); + + GeneratePublicMethods(nameof(readMethods), "ReadMethods", readMethods, xmlMappings); + GeneratePublicMethods("writeMethods", "WriteMethods", writerMethods, xmlMappings); + GenerateTypedSerializers(serializers); + GenerateSupportedTypes(types); + GenerateGetSerializer(serializers, xmlMappings); + + _writer.Indent--; + _writer.WriteLine("}"); + } + + internal static bool IsWildcard(SpecialMapping mapping) + { + if (mapping is SerializableMapping) + return ((SerializableMapping)mapping).IsAny; + return mapping.TypeDesc.CanBeElementValue; + } + } +#endif } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs index 8229bf3465..e891a9c18d 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.IO; using System; @@ -24,11 +20,7 @@ namespace System.Xml.Serialization using System.Xml.Serialization.Configuration; ///<internalonly/> -#if XMLSERIALIZERGENERATOR - internal abstract class XmlSerializationReader : XmlSerializationGeneratedCode -#else public abstract class XmlSerializationReader : XmlSerializationGeneratedCode -#endif { private XmlReader _r; private XmlCountingReader _countingReader; @@ -193,7 +185,6 @@ namespace System.Xml.Serialization InitIDs(); } -#if !XMLSERIALIZERGENERATOR protected bool DecodeName { get @@ -2149,10 +2140,8 @@ namespace System.Xml.Serialization get { return _collectionItems; } } } -#endif } -#if !XMLSERIALIZERGENERATOR ///<internalonly/> public delegate void XmlSerializationFixupCallback(object fixup); @@ -2162,5 +2151,3079 @@ namespace System.Xml.Serialization ///<internalonly/> public delegate object XmlSerializationReadCallback(); + +#if !FEATURE_SERIALIZATION_UAPAOT + internal class XmlSerializationReaderCodeGen : XmlSerializationCodeGen + { + private Hashtable _idNames = new Hashtable(); + private Hashtable _enums; + private Hashtable _createMethods = new Hashtable(); + private int _nextCreateMethodNumber = 0; + private int _nextIdNumber = 0; + private int _nextWhileLoopIndex = 0; + + internal Hashtable Enums + { + get + { + if (_enums == null) + { + _enums = new Hashtable(); + } + return _enums; + } + } + + private class CreateCollectionInfo + { + private string _name; + private TypeDesc _td; + + internal CreateCollectionInfo(string name, TypeDesc td) + { + _name = name; + _td = td; + } + internal string Name + { + get { return _name; } + } + + internal TypeDesc TypeDesc + { + get { return _td; } + } + } + private class Member + { + private string _source; + private string _arrayName; + private string _arraySource; + private string _choiceArrayName; + private string _choiceSource; + private string _choiceArraySource; + private MemberMapping _mapping; + private bool _isArray; + private bool _isList; + private bool _isNullable; + private bool _multiRef; + private int _fixupIndex = -1; + private string _paramsReadSource; + private string _checkSpecifiedSource; + + internal Member(XmlSerializationReaderCodeGen outerClass, string source, string arrayName, int i, MemberMapping mapping) + : this(outerClass, source, null, arrayName, i, mapping, false, null) + { + } + internal Member(XmlSerializationReaderCodeGen outerClass, string source, string arrayName, int i, MemberMapping mapping, string choiceSource) + : this(outerClass, source, null, arrayName, i, mapping, false, choiceSource) + { + } + internal Member(XmlSerializationReaderCodeGen outerClass, string source, string arraySource, string arrayName, int i, MemberMapping mapping) + : this(outerClass, source, arraySource, arrayName, i, mapping, false, null) + { + } + internal Member(XmlSerializationReaderCodeGen outerClass, string source, string arraySource, string arrayName, int i, MemberMapping mapping, string choiceSource) + : this(outerClass, source, arraySource, arrayName, i, mapping, false, choiceSource) + { + } + internal Member(XmlSerializationReaderCodeGen outerClass, string source, string arrayName, int i, MemberMapping mapping, bool multiRef) + : this(outerClass, source, null, arrayName, i, mapping, multiRef, null) + { + } + internal Member(XmlSerializationReaderCodeGen outerClass, string source, string arraySource, string arrayName, int i, MemberMapping mapping, bool multiRef, string choiceSource) + { + _source = source; + _arrayName = arrayName + "_" + i.ToString(CultureInfo.InvariantCulture); + _choiceArrayName = "choice_" + _arrayName; + _choiceSource = choiceSource; + ElementAccessor[] elements = mapping.Elements; + + if (mapping.TypeDesc.IsArrayLike) + { + if (arraySource != null) + _arraySource = arraySource; + else + _arraySource = outerClass.GetArraySource(mapping.TypeDesc, _arrayName, multiRef); + _isArray = mapping.TypeDesc.IsArray; + _isList = !_isArray; + if (mapping.ChoiceIdentifier != null) + { + _choiceArraySource = outerClass.GetArraySource(mapping.TypeDesc, _choiceArrayName, multiRef); + + string a = _choiceArrayName; + string c = "c" + a; + bool choiceUseReflection = mapping.ChoiceIdentifier.Mapping.TypeDesc.UseReflection; + string choiceTypeFullName = mapping.ChoiceIdentifier.Mapping.TypeDesc.CSharpName; + string castString = choiceUseReflection ? "" : "(" + choiceTypeFullName + "[])"; + + string init = a + " = " + castString + + "EnsureArrayIndex(" + a + ", " + c + ", " + outerClass.RaCodeGen.GetStringForTypeof(choiceTypeFullName, choiceUseReflection) + ");"; + _choiceArraySource = init + outerClass.RaCodeGen.GetStringForArrayMember(a, c + "++", mapping.ChoiceIdentifier.Mapping.TypeDesc); + } + else + { + _choiceArraySource = _choiceSource; + } + } + else + { + _arraySource = arraySource == null ? source : arraySource; + _choiceArraySource = _choiceSource; + } + _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 XmlSerializationReaderCodeGen(IndentedWriter writer, TypeScope[] scopes, string access, string className) : base(writer, scopes, access, className) + { + } + + internal void GenerateBegin() + { + Writer.Write(Access); + Writer.Write(" class "); + Writer.Write(ClassName); + Writer.Write(" : "); + Writer.Write(typeof(System.Xml.Serialization.XmlSerializationReader).FullName); + Writer.WriteLine(" {"); + Writer.Indent++; + 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); + } + // pre-generate read methods only for the encoded soap + foreach (TypeScope scope in Scopes) + { + foreach (TypeMapping mapping in scope.TypeMappings) + { + if (!mapping.IsSoap) + continue; + if (mapping is StructMapping) + WriteStructMethod((StructMapping)mapping); + else if (mapping is EnumMapping) + WriteEnumMethod((EnumMapping)mapping); + else if (mapping is NullableMapping) + { + WriteNullableMethod((NullableMapping)mapping); + } + } + } + } + + 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() + { + GenerateEnd(new string[0], new XmlMapping[0], new Type[0]); + } + internal void GenerateEnd(string[] methods, XmlMapping[] xmlMappings, Type[] types) + { + GenerateReferencedMethods(); + GenerateInitCallbacksMethod(); + + foreach (CreateCollectionInfo c in _createMethods.Values) + { + WriteCreateCollectionMethod(c); + } + + Writer.WriteLine(); + foreach (string idName in _idNames.Values) + { + Writer.Write("string "); + Writer.Write(idName); + Writer.WriteLine(";"); + } + + Writer.WriteLine(); + Writer.WriteLine("protected override void InitIDs() {"); + Writer.Indent++; + foreach (string id in _idNames.Keys) + { + // CONSIDER, erikc, switch to enumerating via DictionaryEntry when issue recolved in BCL + string idName = (string)_idNames[id]; + Writer.Write(idName); + Writer.Write(" = Reader.NameTable.Add("); + WriteQuotedCSharpString(id); + Writer.WriteLine(");"); + } + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + + internal string GenerateElement(XmlMapping xmlMapping) + { + if (!xmlMapping.IsReadable) + return null; + if (!xmlMapping.GenerateSerializer) + throw new ArgumentException(SR.XmlInternalError, nameof(xmlMapping)); + if (xmlMapping is XmlTypeMapping) + return GenerateTypeElement((XmlTypeMapping)xmlMapping); + else if (xmlMapping is XmlMembersMapping) + return GenerateMembersElement((XmlMembersMapping)xmlMapping); + else + throw new ArgumentException(SR.XmlInternalError, nameof(xmlMapping)); + } + + private void WriteIsStartTag(string name, string ns) + { + Writer.Write("if (Reader.IsStartElement("); + WriteID(name); + Writer.Write(", "); + WriteID(ns); + Writer.WriteLine(")) {"); + Writer.Indent++; + } + + private void WriteUnknownNode(string func, string node, ElementAccessor e, bool anyIfs) + { + if (anyIfs) + { + Writer.WriteLine("else {"); + Writer.Indent++; + } + Writer.Write(func); + Writer.Write("("); + Writer.Write(node); + if (e != null) + { + Writer.Write(", "); + string expectedElement = e.Form == XmlSchemaForm.Qualified ? e.Namespace : ""; + expectedElement += ":"; + expectedElement += e.Name; + ReflectionAwareCodeGen.WriteQuotedCSharpString(Writer, expectedElement); + } + Writer.WriteLine(");"); + if (anyIfs) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + private void GenerateInitCallbacksMethod() + { + Writer.WriteLine(); + Writer.WriteLine("protected override void InitCallbacks() {"); + Writer.Indent++; + + string dummyArrayMethodName = NextMethodName("Array"); + bool needDummyArrayMethod = false; + foreach (TypeScope scope in Scopes) + { + foreach (TypeMapping mapping in scope.TypeMappings) + { + if (mapping.IsSoap && + (mapping is StructMapping || mapping is EnumMapping || mapping is ArrayMapping || mapping is NullableMapping) && + !mapping.TypeDesc.IsRoot) + { + string methodName; + if (mapping is ArrayMapping) + { + methodName = dummyArrayMethodName; + needDummyArrayMethod = true; + } + else + methodName = (string)MethodNames[mapping]; + + Writer.Write("AddReadCallback("); + WriteID(mapping.TypeName); + Writer.Write(", "); + WriteID(mapping.Namespace); + Writer.Write(", "); + Writer.Write(RaCodeGen.GetStringForTypeof(mapping.TypeDesc.CSharpName, mapping.TypeDesc.UseReflection)); + Writer.Write(", new "); + Writer.Write(typeof(XmlSerializationReadCallback).FullName); + Writer.Write("(this."); + Writer.Write(methodName); + Writer.WriteLine("));"); + } + } + } + + Writer.Indent--; + Writer.WriteLine("}"); + + if (needDummyArrayMethod) + { + Writer.WriteLine(); + Writer.Write("object "); + Writer.Write(dummyArrayMethodName); + Writer.WriteLine("() {"); + Writer.Indent++; + Writer.WriteLine("// dummy array method"); + Writer.WriteLine("UnknownNode(null);"); + Writer.WriteLine("return null;"); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + + private string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) + { + if (xmlMembersMapping.Accessor.IsSoap) + return GenerateEncodedMembersElement(xmlMembersMapping); + else + return GenerateLiteralMembersElement(xmlMembersMapping); + } + + private 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(SR.Format(SR.XmlInternalErrorDetails, "Can not find " + member.ChoiceIdentifier.MemberName + " in the members mapping.")); +#endif + + } + return choiceSource; + } + + private 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); + } + + private 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); + Writer.WriteLine(); + Writer.Write("public object[] "); + Writer.Write(methodName); + Writer.WriteLine("() {"); + Writer.Indent++; + Writer.WriteLine("Reader.MoveToContent();"); + + Writer.Write("object[] p = new object["); + Writer.Write(mappings.Length.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine("];"); + InitializeValueTypes("p", mappings); + + int wrapperLoopIndex = 0; + if (hasWrapperElement) + { + wrapperLoopIndex = WriteWhileNotLoopStart(); + Writer.Indent++; + 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) Writer.WriteLine("IsReturnValue = true;"); + + WriteParamsRead(mappings.Length); + + if (attributeMembersList.Count > 0) + { + Member[] attributeMembers = (Member[])attributeMembersList.ToArray(typeof(Member)); + WriteMemberBegin(attributeMembers); + WriteAttributes(attributeMembers, anyAttribute, "UnknownNode", "(object)p"); + WriteMemberEnd(attributeMembers); + Writer.WriteLine("Reader.MoveToElement();"); + } + + WriteMemberBegin(textOrArrayMembers); + + if (hasWrapperElement) + { + Writer.WriteLine("if (Reader.IsEmptyElement) { Reader.Skip(); Reader.MoveToContent(); continue; }"); + Writer.WriteLine("Reader.ReadStartElement();"); + } + if (IsSequence(members)) + { + Writer.WriteLine("int state = 0;"); + } + int loopIndex = WriteWhileNotLoopStart(); + Writer.Indent++; + + string unknownNode = "UnknownNode((object)p, " + ExpectedElements(members) + ");"; + WriteMemberElements(members, unknownNode, unknownNode, anyElement, anyText, null); + + Writer.WriteLine("Reader.MoveToContent();"); + WriteWhileLoopEnd(loopIndex); + + WriteMemberEnd(textOrArrayMembers); + + if (hasWrapperElement) + { + Writer.WriteLine("ReadEndElement();"); + + Writer.Indent--; + Writer.WriteLine("}"); + + WriteUnknownNode("UnknownNode", "null", element, true); + + Writer.WriteLine("Reader.MoveToContent();"); + WriteWhileLoopEnd(wrapperLoopIndex); + } + + Writer.WriteLine("return p;"); + Writer.Indent--; + Writer.WriteLine("}"); + + return methodName; + } + + private void InitializeValueTypes(string arrayName, MemberMapping[] mappings) + { + for (int i = 0; i < mappings.Length; i++) + { + if (!mappings[i].TypeDesc.IsValueType) + continue; + Writer.Write(arrayName); + Writer.Write("["); + Writer.Write(i.ToString(CultureInfo.InvariantCulture)); + Writer.Write("] = "); + + if (mappings[i].TypeDesc.IsOptionalValue && mappings[i].TypeDesc.BaseTypeDesc.UseReflection) + { + Writer.Write("null"); + } + else + { + Writer.Write(RaCodeGen.GetStringForCreateInstance(mappings[i].TypeDesc.CSharpName, mappings[i].TypeDesc.UseReflection, false, false)); + } + Writer.WriteLine(";"); + } + } + + private string GenerateEncodedMembersElement(XmlMembersMapping xmlMembersMapping) + { + ElementAccessor element = xmlMembersMapping.Accessor; + MembersMapping membersMapping = (MembersMapping)element.Mapping; + MemberMapping[] mappings = membersMapping.Members; + bool hasWrapperElement = membersMapping.HasWrapperElement; + bool writeAccessors = membersMapping.WriteAccessors; + string methodName = NextMethodName(element.Name); + Writer.WriteLine(); + Writer.Write("public object[] "); + Writer.Write(methodName); + Writer.WriteLine("() {"); + Writer.Indent++; + + Writer.WriteLine("Reader.MoveToContent();"); + + Writer.Write("object[] p = new object["); + Writer.Write(mappings.Length.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine("];"); + InitializeValueTypes("p", mappings); + + if (hasWrapperElement) + { + WriteReadNonRoots(); + + if (membersMapping.ValidateRpcWrapperElement) + { + Writer.Write("if (!"); + WriteXmlNodeEqual("Reader", element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""); + Writer.WriteLine(") throw CreateUnknownNodeException();"); + } + Writer.WriteLine("bool isEmptyWrapper = Reader.IsEmptyElement;"); + Writer.WriteLine("Reader.ReadStartElement();"); + } + + Member[] members = new Member[mappings.Length]; + 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 + ")"; + } + Member member = new Member(this, source, arraySource, "a", i, mapping); + if (!mapping.IsSequence) + member.ParamsReadSource = "paramsRead[" + i.ToString(CultureInfo.InvariantCulture) + "]"; + members[i] = member; + + 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; + } + } + } + } + + string fixupMethodName = "fixup_" + methodName; + bool anyFixups = WriteMemberFixupBegin(members, fixupMethodName, "p"); + + if (members.Length > 0 && members[0].Mapping.IsReturnValue) Writer.WriteLine("IsReturnValue = true;"); + + string checkTypeHrefSource = (!hasWrapperElement && !writeAccessors) ? "hrefList" : null; + if (checkTypeHrefSource != null) + WriteInitCheckTypeHrefList(checkTypeHrefSource); + + WriteParamsRead(mappings.Length); + int loopIndex = WriteWhileNotLoopStart(); + Writer.Indent++; + + string unrecognizedElementSource = checkTypeHrefSource == null ? "UnknownNode((object)p);" : "if (Reader.GetAttribute(\"id\", null) != null) { ReadReferencedElement(); } else { UnknownNode((object)p); }"; + WriteMemberElements(members, unrecognizedElementSource, "UnknownNode((object)p);", null, null, checkTypeHrefSource); + Writer.WriteLine("Reader.MoveToContent();"); + + WriteWhileLoopEnd(loopIndex); + + if (hasWrapperElement) + Writer.WriteLine("if (!isEmptyWrapper) ReadEndElement();"); + + if (checkTypeHrefSource != null) + WriteHandleHrefList(members, checkTypeHrefSource); + + Writer.WriteLine("ReadReferencedElements();"); + Writer.WriteLine("return p;"); + + Writer.Indent--; + Writer.WriteLine("}"); + + if (anyFixups) WriteFixupMethod(fixupMethodName, members, "object[]", false, false, "p"); + + return methodName; + } + + private void WriteCreateCollection(TypeDesc td, string source) + { + bool useReflection = td.UseReflection; + string item = (td.ArrayElementTypeDesc == null ? "object" : td.ArrayElementTypeDesc.CSharpName) + "[]"; + bool arrayElementUseReflection = td.ArrayElementTypeDesc == null ? false : td.ArrayElementTypeDesc.UseReflection; + + //cannot call WriteArrayLocalDecl since 'ci' is always + //array and 'td' corresponds to 'c' + if (arrayElementUseReflection) + item = typeof(Array).FullName; + Writer.Write(item); + Writer.Write(" "); + Writer.Write("ci ="); + Writer.Write("(" + item + ")"); + Writer.Write(source); + Writer.WriteLine(";"); + + Writer.WriteLine("for (int i = 0; i < ci.Length; i++) {"); + Writer.Indent++; + Writer.Write(RaCodeGen.GetStringForMethod("c", td.CSharpName, "Add", useReflection)); + + //cannot call GetStringForArrayMember since 'ci' is always + //array and 'td' corresponds to 'c' + if (!arrayElementUseReflection) + Writer.Write("ci[i]"); + else + Writer.Write(RaCodeGen.GetReflectionVariable(typeof(Array).FullName, "0") + "[ci , i]"); + + + if (useReflection) Writer.WriteLine("}"); + Writer.WriteLine(");"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) + { + ElementAccessor element = xmlTypeMapping.Accessor; + TypeMapping mapping = element.Mapping; + string methodName = NextMethodName(element.Name); + Writer.WriteLine(); + Writer.Write("public object "); + Writer.Write(methodName); + Writer.WriteLine("() {"); + Writer.Indent++; + Writer.WriteLine("object o = null;"); + 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) }; + Writer.WriteLine("Reader.MoveToContent();"); + string unknownNode = "UnknownNode(null, " + ExpectedElements(members) + ");"; + WriteMemberElements(members, "throw CreateUnknownNodeException();", unknownNode, element.Any ? members[0] : null, null, null); + if (element.IsSoap) + { + Writer.WriteLine("Referenced(o);"); + Writer.WriteLine("ReadReferencedElements();"); + } + Writer.WriteLine("return (object)o;"); + Writer.Indent--; + Writer.WriteLine("}"); + return methodName; + } + + private string NextMethodName(string name) + { + return "Read" + (++NextMethodNumber).ToString(CultureInfo.InvariantCulture) + "_" + CodeIdentifier.MakeValidInternal(name); + } + + private string NextIdName(string name) + { + return "id" + (++_nextIdNumber).ToString(CultureInfo.InvariantCulture) + "_" + CodeIdentifier.MakeValidInternal(name); + } + + private void WritePrimitive(TypeMapping mapping, string source) + { + if (mapping is EnumMapping) + { + string enumMethodName = ReferenceMapping(mapping); + if (enumMethodName == null) throw new InvalidOperationException(SR.Format(SR.XmlMissingMethodEnum, mapping.TypeDesc.Name)); + if (mapping.IsSoap) + { + // SOAP methods are not strongly-typed (the return object), so we need to add a cast + Writer.Write("("); + Writer.Write(mapping.TypeDesc.CSharpName); + Writer.Write(")"); + } + Writer.Write(enumMethodName); + Writer.Write("("); + if (!mapping.IsSoap) Writer.Write(source); + Writer.Write(")"); + } + else if (mapping.TypeDesc == StringTypeDesc) + { + Writer.Write(source); + } + else if (mapping.TypeDesc.FormatterName == "String") + { + if (mapping.TypeDesc.CollapseWhitespace) + { + Writer.Write("CollapseWhitespace("); + Writer.Write(source); + Writer.Write(")"); + } + else + { + Writer.Write(source); + } + } + else + { + if (!mapping.TypeDesc.HasCustomFormatter) + { + Writer.Write(typeof(XmlConvert).FullName); + Writer.Write("."); + } + Writer.Write("To"); + Writer.Write(mapping.TypeDesc.FormatterName); + Writer.Write("("); + Writer.Write(source); + Writer.Write(")"); + } + } + + private 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; + } + + private string WriteHashtable(EnumMapping mapping, string typeName) + { + 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); + + Writer.WriteLine(); + Writer.Write(typeof(Hashtable).FullName); + Writer.Write(" "); + Writer.Write(memberName); + Writer.WriteLine(";"); + Writer.WriteLine(); + + Writer.Write("internal "); + Writer.Write(typeof(Hashtable).FullName); + Writer.Write(" "); + Writer.Write(propName); + Writer.WriteLine(" {"); + Writer.Indent++; + + Writer.WriteLine("get {"); + Writer.Indent++; + + Writer.Write("if ((object)"); + Writer.Write(memberName); + Writer.WriteLine(" == null) {"); + Writer.Indent++; + + Writer.Write(typeof(Hashtable).FullName); + Writer.Write(" h = new "); + Writer.Write(typeof(Hashtable).FullName); + Writer.WriteLine("();"); + + ConstantMapping[] constants = mapping.Constants; + + for (int i = 0; i < constants.Length; i++) + { + Writer.Write("h.Add("); + WriteQuotedCSharpString(constants[i].XmlName); + if (!mapping.TypeDesc.UseReflection) + { + Writer.Write(", (long)"); + Writer.Write(mapping.TypeDesc.CSharpName); + Writer.Write(".@"); + CodeIdentifier.CheckValidIdentifier(constants[i].Name); + Writer.Write(constants[i].Name); + } + else + { + Writer.Write(", "); + Writer.Write(constants[i].Value.ToString(CultureInfo.InvariantCulture) + "L"); + } + + Writer.WriteLine(");"); + } + + Writer.Write(memberName); + Writer.WriteLine(" = h;"); + + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.Write("return "); + Writer.Write(memberName); + Writer.WriteLine(";"); + + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.Indent--; + Writer.WriteLine("}"); + + return propName; + } + + private void WriteEnumMethod(EnumMapping mapping) + { + string tableName = null; + if (mapping.IsFlags) + tableName = WriteHashtable(mapping, mapping.TypeDesc.Name); + + string methodName = (string)MethodNames[mapping]; + Writer.WriteLine(); + bool useReflection = mapping.TypeDesc.UseReflection; + string fullTypeName = mapping.TypeDesc.CSharpName; + + if (mapping.IsSoap) + { + Writer.Write("object"); + Writer.Write(" "); + Writer.Write(methodName); + Writer.WriteLine("() {"); + Writer.Indent++; + Writer.WriteLine("string s = Reader.ReadElementString();"); + } + else + { + Writer.Write(useReflection ? "object" : fullTypeName); + Writer.Write(" "); + Writer.Write(methodName); + Writer.WriteLine("(string s) {"); + Writer.Indent++; + } + + ConstantMapping[] constants = mapping.Constants; + if (mapping.IsFlags) + { + if (useReflection) + { + Writer.Write("return "); + Writer.Write(typeof(Enum).FullName); + Writer.Write(".ToObject("); + Writer.Write(RaCodeGen.GetStringForTypeof(fullTypeName, useReflection)); + Writer.Write(", ToEnum(s, "); + Writer.Write(tableName); + Writer.Write(", "); + WriteQuotedCSharpString(fullTypeName); + Writer.WriteLine("));"); + } + else + { + Writer.Write("return ("); + Writer.Write(fullTypeName); + Writer.Write(")ToEnum(s, "); + Writer.Write(tableName); + Writer.Write(", "); + WriteQuotedCSharpString(fullTypeName); + Writer.WriteLine(");"); + } + } + else + { + Writer.WriteLine("switch (s) {"); + Writer.Indent++; + 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) + { + Writer.Write("case "); + WriteQuotedCSharpString(c.XmlName); + Writer.Write(": return "); + Writer.Write(RaCodeGen.GetStringForEnumMember(fullTypeName, c.Name, useReflection)); + Writer.WriteLine(";"); + cases[c.XmlName] = c.XmlName; + } + } + + Writer.Write("default: throw CreateUnknownConstantException(s, "); + Writer.Write(RaCodeGen.GetStringForTypeof(fullTypeName, useReflection)); + Writer.WriteLine(");"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteDerivedTypes(StructMapping mapping, bool isTypedReturn, string returnTypeName) + { + for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) + { + Writer.Write("else if ("); + WriteQNameEqual("xsiType", derived.TypeName, derived.Namespace); + Writer.WriteLine(")"); + Writer.Indent++; + + 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(SR.Format(SR.XmlInternalErrorMethod, derived.TypeDesc.Name)); +#endif + + Writer.Write("return "); + if (derived.TypeDesc.UseReflection && isTypedReturn) + Writer.Write("(" + returnTypeName + ")"); + Writer.Write(methodName); + Writer.Write("("); + if (derived.TypeDesc.IsNullable) + Writer.Write("isNullable, "); + Writer.WriteLine("false);"); + + Writer.Indent--; + + WriteDerivedTypes(derived, isTypedReturn, returnTypeName); + } + } + + private void WriteEnumAndArrayTypes() + { + foreach (TypeScope scope in Scopes) + { + foreach (Mapping m in scope.TypeMappings) + { + if (m.IsSoap) + continue; + if (m is EnumMapping) + { + EnumMapping mapping = (EnumMapping)m; + Writer.Write("else if ("); + WriteQNameEqual("xsiType", mapping.TypeName, mapping.Namespace); + Writer.WriteLine(") {"); + Writer.Indent++; + Writer.WriteLine("Reader.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(SR.Format(SR.XmlInternalErrorMethod, mapping.TypeDesc.Name)); +#endif + Writer.Write("object e = "); + Writer.Write(methodName); + Writer.WriteLine("(CollapseWhitespace(Reader.ReadString()));"); + Writer.WriteLine("ReadEndElement();"); + Writer.WriteLine("return e;"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else if (m is ArrayMapping) + { + ArrayMapping mapping = (ArrayMapping)m; + if (mapping.TypeDesc.HasDefaultConstructor) + { + Writer.Write("else if ("); + WriteQNameEqual("xsiType", mapping.TypeName, mapping.Namespace); + Writer.WriteLine(") {"); + Writer.Indent++; + MemberMapping memberMapping = new MemberMapping(); + memberMapping.TypeDesc = mapping.TypeDesc; + memberMapping.Elements = mapping.Elements; + Member member = new Member(this, "a", "z", 0, memberMapping); + + TypeDesc td = mapping.TypeDesc; + string fullTypeName = mapping.TypeDesc.CSharpName; + if (td.UseReflection) + { + if (td.IsArray) + Writer.Write(typeof(Array).FullName); + else + Writer.Write("object"); + } + else + Writer.Write(fullTypeName); + Writer.Write(" a = "); + if (mapping.TypeDesc.IsValueType) + { + Writer.Write(RaCodeGen.GetStringForCreateInstance(fullTypeName, td.UseReflection, false, false)); + Writer.WriteLine(";"); + } + else + Writer.WriteLine("null;"); + + WriteArray(member.Source, member.ArrayName, mapping, false, false, -1); + Writer.WriteLine("return a;"); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + } + } + } + + private void WriteNullableMethod(NullableMapping nullableMapping) + { + string methodName = (string)MethodNames[nullableMapping]; + bool useReflection = nullableMapping.BaseMapping.TypeDesc.UseReflection; + string typeName = useReflection ? "object" : nullableMapping.TypeDesc.CSharpName; + Writer.WriteLine(); + + Writer.Write(typeName); + Writer.Write(" "); + Writer.Write(methodName); + Writer.WriteLine("(bool checkType) {"); + Writer.Indent++; + + Writer.Write(typeName); + Writer.Write(" o = "); + + if (useReflection) + { + Writer.Write("null"); + } + else + { + Writer.Write("default("); + Writer.Write(typeName); + Writer.Write(")"); + } + Writer.WriteLine(";"); + + Writer.WriteLine("if (ReadNull())"); + Writer.Indent++; + + Writer.WriteLine("return o;"); + Writer.Indent--; + + 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); + Writer.WriteLine("return o;"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteStructMethod(StructMapping structMapping) + { + if (structMapping.IsSoap) + WriteEncodedStructMethod(structMapping); + else + WriteLiteralStructMethod(structMapping); + } + + private void WriteLiteralStructMethod(StructMapping structMapping) + { + string methodName = (string)MethodNames[structMapping]; + bool useReflection = structMapping.TypeDesc.UseReflection; + string typeName = useReflection ? "object" : structMapping.TypeDesc.CSharpName; + Writer.WriteLine(); + Writer.Write(typeName); + Writer.Write(" "); + Writer.Write(methodName); + Writer.Write("("); + if (structMapping.TypeDesc.IsNullable) + Writer.Write("bool isNullable, "); + Writer.WriteLine("bool checkType) {"); + Writer.Indent++; + + Writer.Write(typeof(XmlQualifiedName).FullName); + Writer.WriteLine(" xsiType = checkType ? GetXsiType() : null;"); + Writer.WriteLine("bool isNull = false;"); + if (structMapping.TypeDesc.IsNullable) + Writer.WriteLine("if (isNullable) isNull = ReadNull();"); + + Writer.WriteLine("if (checkType) {"); + if (structMapping.TypeDesc.IsRoot) + { + Writer.Indent++; + Writer.WriteLine("if (isNull) {"); + Writer.Indent++; + Writer.WriteLine("if (xsiType != null) return (" + typeName + ")ReadTypedNull(xsiType);"); + Writer.Write("else return "); + if (structMapping.TypeDesc.IsValueType) + { + Writer.Write(RaCodeGen.GetStringForCreateInstance(structMapping.TypeDesc.CSharpName, useReflection, false, false)); + Writer.WriteLine(";"); + } + else + Writer.WriteLine("null;"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.Write("if (xsiType == null"); + if (!structMapping.TypeDesc.IsRoot) + { + Writer.Write(" || "); + WriteQNameEqual("xsiType", structMapping.TypeName, structMapping.Namespace); + } + Writer.WriteLine(") {"); + if (structMapping.TypeDesc.IsRoot) + { + Writer.Indent++; + Writer.WriteLine("return ReadTypedPrimitive(new System.Xml.XmlQualifiedName(\"" + Soap.UrType + "\", \"" + XmlSchema.Namespace + "\"));"); + Writer.Indent--; + } + Writer.WriteLine("}"); + WriteDerivedTypes(structMapping, !useReflection && !structMapping.TypeDesc.IsRoot, typeName); + if (structMapping.TypeDesc.IsRoot) WriteEnumAndArrayTypes(); + Writer.WriteLine("else"); + Writer.Indent++; + if (structMapping.TypeDesc.IsRoot) + Writer.Write("return ReadTypedPrimitive(("); + else + Writer.Write("throw CreateUnknownTypeException(("); + Writer.Write(typeof(XmlQualifiedName).FullName); + Writer.WriteLine(")xsiType);"); + Writer.Indent--; + Writer.WriteLine("}"); + + if (structMapping.TypeDesc.IsNullable) + Writer.WriteLine("if (isNull) return null;"); + + if (structMapping.TypeDesc.IsAbstract) + { + Writer.Write("throw CreateAbstractTypeException("); + WriteQuotedCSharpString(structMapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(structMapping.Namespace); + Writer.WriteLine(");"); + } + else + { + if (structMapping.TypeDesc.Type != null && typeof(XmlSchemaObject).IsAssignableFrom(structMapping.TypeDesc.Type)) + { + Writer.WriteLine("DecodeName = false;"); + } + WriteCreateMapping(structMapping, "o"); + + MemberMapping[] mappings = TypeScope.GetSettableMembers(structMapping); + + 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(SR.Format(SR.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", "(object)o"); + if (anyAttribute != null) + WriteMemberEnd(arraysToDeclare); + + Writer.WriteLine("Reader.MoveToElement();"); + + Writer.WriteLine("if (Reader.IsEmptyElement) {"); + Writer.Indent++; + Writer.WriteLine("Reader.Skip();"); + WriteMemberEnd(arraysToSet); + Writer.WriteLine("return o;"); + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.WriteLine("Reader.ReadStartElement();"); + if (IsSequence(allMembers)) + { + Writer.WriteLine("int state = 0;"); + } + int loopIndex = WriteWhileNotLoopStart(); + Writer.Indent++; + string unknownNode = "UnknownNode((object)o, " + ExpectedElements(allMembers) + ");"; + WriteMemberElements(allMembers, unknownNode, unknownNode, anyElement, anyText, null); + Writer.WriteLine("Reader.MoveToContent();"); + + WriteWhileLoopEnd(loopIndex); + WriteMemberEnd(arraysToSet); + + Writer.WriteLine("ReadEndElement();"); + Writer.WriteLine("return o;"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteEncodedStructMethod(StructMapping structMapping) + { + if (structMapping.TypeDesc.IsRoot) + return; + bool useReflection = structMapping.TypeDesc.UseReflection; + string methodName = (string)MethodNames[structMapping]; + Writer.WriteLine(); + Writer.Write("object"); + Writer.Write(" "); + Writer.Write(methodName); + Writer.Write("("); + Writer.WriteLine(") {"); + Writer.Indent++; + + Member[] members; + bool anyFixups; + string fixupMethodName; + + if (structMapping.TypeDesc.IsAbstract) + { + Writer.Write("throw CreateAbstractTypeException("); + WriteQuotedCSharpString(structMapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(structMapping.Namespace); + Writer.WriteLine(");"); + members = new Member[0]; + anyFixups = false; + fixupMethodName = null; + } + else + { + WriteCreateMapping(structMapping, "o"); + + MemberMapping[] mappings = TypeScope.GetSettableMembers(structMapping); + members = new Member[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, source, "a", i, mapping, GetChoiceIdentifierSource(mapping, "o", structMapping.TypeDesc)); + if (mapping.CheckSpecified == SpecifiedAccessor.ReadWrite) + member.CheckSpecifiedSource = RaCodeGen.GetStringForMember("o", mapping.Name + "Specified", structMapping.TypeDesc); + if (!mapping.IsSequence) + member.ParamsReadSource = "paramsRead[" + i.ToString(CultureInfo.InvariantCulture) + "]"; + members[i] = member; + } + + fixupMethodName = "fixup_" + methodName; + anyFixups = WriteMemberFixupBegin(members, fixupMethodName, "o"); + + // we're able to not do WriteMemberBegin here because we don't allow arrays as attributes + + WriteParamsRead(mappings.Length); + WriteAttributes(members, null, "UnknownNode", "(object)o"); + Writer.WriteLine("Reader.MoveToElement();"); + + Writer.WriteLine("if (Reader.IsEmptyElement) { Reader.Skip(); return o; }"); + Writer.WriteLine("Reader.ReadStartElement();"); + + int loopIndex = WriteWhileNotLoopStart(); + Writer.Indent++; + + WriteMemberElements(members, "UnknownNode((object)o);", "UnknownNode((object)o);", null, null, null); + Writer.WriteLine("Reader.MoveToContent();"); + + WriteWhileLoopEnd(loopIndex); + + Writer.WriteLine("ReadEndElement();"); + Writer.WriteLine("return o;"); + } + Writer.Indent--; + Writer.WriteLine("}"); + + if (anyFixups) WriteFixupMethod(fixupMethodName, members, structMapping.TypeDesc.CSharpName, structMapping.TypeDesc.UseReflection, true, "o"); + } + + private void WriteFixupMethod(string fixupMethodName, Member[] members, string typeName, bool useReflection, bool typed, string source) + { + Writer.WriteLine(); + Writer.Write("void "); + Writer.Write(fixupMethodName); + Writer.WriteLine("(object objFixup) {"); + Writer.Indent++; + Writer.WriteLine("Fixup fixup = (Fixup)objFixup;"); + WriteLocalDecl(typeName, source, "fixup.Source", useReflection); + Writer.WriteLine("string[] ids = fixup.Ids;"); + + for (int i = 0; i < members.Length; i++) + { + Member member = members[i]; + if (member.MultiRef) + { + string fixupIndex = member.FixupIndex.ToString(CultureInfo.InvariantCulture); + Writer.Write("if (ids["); + Writer.Write(fixupIndex); + Writer.WriteLine("] != null) {"); + Writer.Indent++; + + string memberSource = /*member.IsList ? source + ".Add(" :*/ member.ArraySource; + + string targetSource = "GetTarget(ids[" + fixupIndex + "])"; + TypeDesc td = member.Mapping.TypeDesc; + if (td.IsCollection || td.IsEnumerable) + { + WriteAddCollectionFixup(td, member.Mapping.ReadOnly, memberSource, targetSource); + } + else + { + if (typed) + { + Writer.WriteLine("try {"); + Writer.Indent++; + WriteSourceBeginTyped(memberSource, member.Mapping.TypeDesc); + } + else + WriteSourceBegin(memberSource); + + Writer.Write(targetSource); + WriteSourceEnd(memberSource); + Writer.WriteLine(";"); + + if (member.Mapping.CheckSpecified == SpecifiedAccessor.ReadWrite && member.CheckSpecifiedSource != null && member.CheckSpecifiedSource.Length > 0) + { + Writer.Write(member.CheckSpecifiedSource); + Writer.WriteLine(" = true;"); + } + + if (typed) + { + WriteCatchCastException(member.Mapping.TypeDesc, targetSource, "ids[" + fixupIndex + "]"); + } + } + Writer.Indent--; + Writer.WriteLine("}"); + } + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteAddCollectionFixup(TypeDesc typeDesc, bool readOnly, string memberSource, string targetSource) + { + Writer.WriteLine("// get array of the collection items"); + bool useReflection = typeDesc.UseReflection; + CreateCollectionInfo create = (CreateCollectionInfo)_createMethods[typeDesc]; + if (create == null) + { + string createName = "create" + (++_nextCreateMethodNumber).ToString(CultureInfo.InvariantCulture) + "_" + typeDesc.Name; + create = new CreateCollectionInfo(createName, typeDesc); + _createMethods.Add(typeDesc, create); + } + + Writer.Write("if ((object)("); + Writer.Write(memberSource); + Writer.WriteLine(") == null) {"); + Writer.Indent++; + + if (readOnly) + { + Writer.Write("throw CreateReadOnlyCollectionException("); + WriteQuotedCSharpString(typeDesc.CSharpName); + Writer.WriteLine(");"); + } + else + { + Writer.Write(memberSource); + Writer.Write(" = "); + Writer.Write(RaCodeGen.GetStringForCreateInstance(typeDesc.CSharpName, typeDesc.UseReflection, typeDesc.CannotNew, true)); + Writer.WriteLine(";"); + } + + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.Write("CollectionFixup collectionFixup = new CollectionFixup("); + Writer.Write(memberSource); + Writer.Write(", "); + Writer.Write("new "); + Writer.Write(typeof(XmlSerializationCollectionFixupCallback).FullName); + Writer.Write("(this."); + Writer.Write(create.Name); + Writer.Write("), "); + Writer.Write(targetSource); + Writer.WriteLine(");"); + Writer.WriteLine("AddFixup(collectionFixup);"); + } + + private void WriteCreateCollectionMethod(CreateCollectionInfo c) + { + Writer.Write("void "); + Writer.Write(c.Name); + Writer.WriteLine("(object collection, object collectionItems) {"); + Writer.Indent++; + + Writer.WriteLine("if (collectionItems == null) return;"); + Writer.WriteLine("if (collection == null) return;"); + + TypeDesc td = c.TypeDesc; + bool useReflection = td.UseReflection; + string fullTypeName = td.CSharpName; + WriteLocalDecl(fullTypeName, nameof(c), "collection", useReflection); + + WriteCreateCollection(td, "collectionItems"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteQNameEqual(string source, string name, string ns) + { + Writer.Write("((object) (("); + Writer.Write(typeof(XmlQualifiedName).FullName); + Writer.Write(")"); + Writer.Write(source); + Writer.Write(").Name == (object)"); + WriteID(name); + Writer.Write(" && (object) (("); + Writer.Write(typeof(XmlQualifiedName).FullName); + Writer.Write(")"); + Writer.Write(source); + Writer.Write(").Namespace == (object)"); + WriteID(ns); + Writer.Write(")"); + } + + private void WriteXmlNodeEqual(string source, string name, string ns) + { + Writer.Write("("); + if (name != null && name.Length > 0) + { + Writer.Write("(object) "); + Writer.Write(source); + Writer.Write(".LocalName == (object)"); + WriteID(name); + Writer.Write(" && "); + } + Writer.Write("(object) "); + Writer.Write(source); + Writer.Write(".NamespaceURI == (object)"); + WriteID(ns); + Writer.Write(")"); + } + + private 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); + } + Writer.Write(idName); + } + + private void WriteAttributes(Member[] members, Member anyAttribute, string elseCall, string firstParam) + { + int count = 0; + Member xmlnsMember = null; + ArrayList attributes = new ArrayList(); + + Writer.WriteLine("while (Reader.MoveToNextAttribute()) {"); + Writer.Indent++; + + 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) + Writer.Write("else "); + + Writer.Write("if ("); + if (member.ParamsReadSource != null) + { + Writer.Write("!"); + Writer.Write(member.ParamsReadSource); + Writer.Write(" && "); + } + + if (attribute.IsSpecialXmlNamespace) + { + WriteXmlNodeEqual("Reader", attribute.Name, XmlReservedNs.NsXml); + } + else + WriteXmlNodeEqual("Reader", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : ""); + Writer.WriteLine(") {"); + Writer.Indent++; + + WriteAttribute(member); + Writer.Indent--; + Writer.WriteLine("}"); + } + + if (count > 0) + Writer.Write("else "); + + if (xmlnsMember != null) + { + Writer.WriteLine("if (IsXmlnsAttribute(Reader.Name)) {"); + Writer.Indent++; + + Writer.Write("if ("); + Writer.Write(xmlnsMember.Source); + Writer.Write(" == null) "); + Writer.Write(xmlnsMember.Source); + Writer.Write(" = new "); + Writer.Write(xmlnsMember.Mapping.TypeDesc.CSharpName); + Writer.WriteLine("();"); + + //Writer.Write(xmlnsMember.ArraySource); + Writer.Write("((" + xmlnsMember.Mapping.TypeDesc.CSharpName + ")" + xmlnsMember.ArraySource + ")"); + Writer.WriteLine(".Add(Reader.Name.Length == 5 ? \"\" : Reader.LocalName, Reader.Value);"); + + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.WriteLine("else {"); + Writer.Indent++; + } + else + { + Writer.WriteLine("if (!IsXmlnsAttribute(Reader.Name)) {"); + Writer.Indent++; + } + if (anyAttribute != null) + { + Writer.Write(typeof(XmlAttribute).FullName); + Writer.Write(" attr = "); + Writer.Write("("); + Writer.Write(typeof(XmlAttribute).FullName); + Writer.WriteLine(") Document.ReadNode(Reader);"); + Writer.WriteLine("ParseWsdlArrayType(attr);"); + WriteAttribute(anyAttribute); + } + else + { + Writer.Write(elseCall); + Writer.Write("("); + Writer.Write(firstParam); + if (attributes.Count > 0) + { + Writer.Write(", "); + 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; + } + WriteQuotedCSharpString(qnames); + } + Writer.WriteLine(");"); + } + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + + private 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); + Writer.Write("attr"); + WriteSourceEnd(member.ArraySource); + Writer.WriteLine(";"); + } + else if (special.TypeDesc.CanBeAttributeValue) + { + Writer.Write("if (attr is "); + Writer.Write(typeof(XmlAttribute).FullName); + Writer.WriteLine(") {"); + Writer.Indent++; + WriteSourceBegin(member.ArraySource); + Writer.Write("("); + Writer.Write(typeof(XmlAttribute).FullName); + Writer.Write(")attr"); + WriteSourceEnd(member.ArraySource); + Writer.WriteLine(";"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + throw new InvalidOperationException(SR.XmlInternalError); + } + else + { + if (attribute.IsList) + { + Writer.WriteLine("string listValues = Reader.Value;"); + Writer.WriteLine("string[] vals = listValues.Split(null);"); + Writer.WriteLine("for (int i = 0; i < vals.Length; i++) {"); + Writer.Indent++; + + string attributeSource = GetArraySource(member.Mapping.TypeDesc, member.ArrayName); + + WriteSourceBegin(attributeSource); + WritePrimitive(attribute.Mapping, "vals[i]"); + WriteSourceEnd(attributeSource); + Writer.WriteLine(";"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + WriteSourceBegin(member.ArraySource); + WritePrimitive(attribute.Mapping, attribute.IsList ? "vals[i]" : "Reader.Value"); + WriteSourceEnd(member.ArraySource); + Writer.WriteLine(";"); + } + } + if (member.Mapping.CheckSpecified == SpecifiedAccessor.ReadWrite && member.CheckSpecifiedSource != null && member.CheckSpecifiedSource.Length > 0) + { + Writer.Write(member.CheckSpecifiedSource); + Writer.WriteLine(" = true;"); + } + if (member.ParamsReadSource != null) + { + Writer.Write(member.ParamsReadSource); + Writer.WriteLine(" = true;"); + } + } + + private bool WriteMemberFixupBegin(Member[] members, string fixupMethodName, string source) + { + int fixupCount = 0; + for (int i = 0; i < members.Length; i++) + { + Member member = (Member)members[i]; + if (member.Mapping.Elements.Length == 0) + continue; + + TypeMapping mapping = member.Mapping.Elements[0].Mapping; + if (mapping is StructMapping || mapping is ArrayMapping || mapping is PrimitiveMapping || mapping is NullableMapping) + { + member.MultiRef = true; + member.FixupIndex = fixupCount++; + } + } + + if (fixupCount > 0) + { + Writer.Write("Fixup fixup = new Fixup("); + Writer.Write(source); + Writer.Write(", "); + Writer.Write("new "); + Writer.Write(typeof(XmlSerializationFixupCallback).FullName); + Writer.Write("(this."); + Writer.Write(fixupMethodName); + Writer.Write("), "); + Writer.Write(fixupCount.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine(");"); + Writer.WriteLine("AddFixup(fixup);"); + return true; + } + return false; + } + + private 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; + string typeDescFullName = typeDesc.CSharpName; + + if (member.Mapping.TypeDesc.IsArray) + { + WriteArrayLocalDecl(typeDesc.CSharpName, + a, "null", typeDesc); + Writer.Write("int "); + Writer.Write(c); + Writer.WriteLine(" = 0;"); + + if (member.Mapping.ChoiceIdentifier != null) + { + WriteArrayLocalDecl(member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.CSharpName + "[]", + member.ChoiceArrayName, "null", + member.Mapping.ChoiceIdentifier.Mapping.TypeDesc); + Writer.Write("int c"); + Writer.Write(member.ChoiceArrayName); + Writer.WriteLine(" = 0;"); + } + } + else + { + bool useReflection = typeDesc.UseReflection; + if (member.Source[member.Source.Length - 1] == '(' || member.Source[member.Source.Length - 1] == '{') + { + WriteCreateInstance(typeDescFullName, a, useReflection, typeDesc.CannotNew); + Writer.Write(member.Source); + Writer.Write(a); + if (member.Source[member.Source.Length - 1] == '{') + Writer.WriteLine("});"); + else + Writer.WriteLine(");"); + } + else + { + if (member.IsList && !member.Mapping.ReadOnly && member.Mapping.TypeDesc.IsNullable) + { + // we need to new the Collections and ArrayLists + Writer.Write("if ((object)("); + Writer.Write(member.Source); + Writer.Write(") == null) "); + if (!member.Mapping.TypeDesc.HasDefaultConstructor) + { + Writer.Write("throw CreateReadOnlyCollectionException("); + WriteQuotedCSharpString(member.Mapping.TypeDesc.CSharpName); + Writer.WriteLine(");"); + } + else + { + Writer.Write(member.Source); + Writer.Write(" = "); + Writer.Write(RaCodeGen.GetStringForCreateInstance(typeDescFullName, useReflection, typeDesc.CannotNew, true)); + Writer.WriteLine(";"); + } + } + WriteLocalDecl(typeDescFullName, a, member.Source, useReflection); + } + } + } + } + } + + private 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; + } + } + StringWriter writer = new StringWriter(CultureInfo.InvariantCulture); + ReflectionAwareCodeGen.WriteQuotedCSharpString(new IndentedWriter(writer, true), qnames); + return writer.ToString(); + } + + private void WriteMemberElements(Member[] members, string elementElseString, string elseString, Member anyElement, Member anyText, string checkTypeHrefsSource) + { + bool checkType = (checkTypeHrefsSource != null && checkTypeHrefsSource.Length > 0); + + if (anyText != null) + { + Writer.WriteLine("string tmp = null;"); + } + + Writer.Write("if (Reader.NodeType == "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".Element) {"); + Writer.Indent++; + + if (checkType) + { + WriteIfNotSoapRoot(elementElseString + " continue;"); + WriteMemberElementsCheckType(checkTypeHrefsSource); + } + else + { + WriteMemberElementsIf(members, anyElement, elementElseString, null); + } + + Writer.Indent--; + Writer.WriteLine("}"); + + if (anyText != null) + WriteMemberText(anyText, elseString); + + Writer.WriteLine("else {"); + Writer.Indent++; + Writer.WriteLine(elseString); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteMemberText(Member anyText, string elseString) + { + Writer.Write("else if (Reader.NodeType == "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".Text || "); + Writer.Write("Reader.NodeType == "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".CDATA || "); + Writer.Write("Reader.NodeType == "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".Whitespace || "); + Writer.Write("Reader.NodeType == "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".SignificantWhitespace) {"); + Writer.Indent++; + + if (anyText != null) + { + WriteText(anyText); + } + else + { + Writer.Write(elseString); + Writer.WriteLine(";"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private 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: + Writer.Write("Document.CreateTextNode(Reader.ReadString())"); + break; + default: + throw new InvalidOperationException(SR.XmlInternalError); + } + WriteSourceEnd(member.ArraySource); + } + else + { + if (member.IsArrayLike) + { + WriteSourceBegin(member.ArraySource); + if (text.Mapping.TypeDesc.CollapseWhitespace) + { + Writer.Write("CollapseWhitespace(Reader.ReadString())"); + } + else + { + Writer.Write("Reader.ReadString()"); + } + } + else + { + if (text.Mapping.TypeDesc == StringTypeDesc || text.Mapping.TypeDesc.FormatterName == "String") + { + Writer.Write("tmp = ReadString(tmp, "); + if (text.Mapping.TypeDesc.CollapseWhitespace) + Writer.WriteLine("true);"); + else + Writer.WriteLine("false);"); + + WriteSourceBegin(member.ArraySource); + Writer.Write("tmp"); + } + else + { + WriteSourceBegin(member.ArraySource); + WritePrimitive(text.Mapping, "Reader.ReadString()"); + } + } + WriteSourceEnd(member.ArraySource); + } + + Writer.WriteLine(";"); + } + + private void WriteMemberElementsCheckType(string checkTypeHrefsSource) + { + Writer.WriteLine("string refElemId = null;"); + Writer.WriteLine("object refElem = ReadReferencingElement(null, null, true, out refElemId);"); + + Writer.WriteLine("if (refElemId != null) {"); + Writer.Indent++; + Writer.Write(checkTypeHrefsSource); + Writer.WriteLine(".Add(refElemId);"); + Writer.Write(checkTypeHrefsSource); + Writer.WriteLine("IsObject.Add(false);"); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else if (refElem != null) {"); + Writer.Indent++; + Writer.Write(checkTypeHrefsSource); + Writer.WriteLine(".Add(refElem);"); + Writer.Write(checkTypeHrefsSource); + Writer.WriteLine("IsObject.Add(true);"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private 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 + { + Writer.WriteLine(elementElseString); + } + } + + private 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; + } + private void WriteMemberElementsIf(Member[] members, Member anyElement, string elementElseString, string checkTypeSource) + { + bool checkType = checkTypeSource != null && checkTypeSource.Length > 0; + //int count = checkType ? 1 : 0; + int count = 0; + + bool isSequence = IsSequence(members); + if (isSequence) + { + Writer.WriteLine("switch (state) {"); + } + 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)) + { + Writer.Write("else "); + } + else if (isSequence) + { + Writer.Write("case "); + Writer.Write(cases.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine(":"); + Writer.Indent++; + } + count++; + firstElement = false; + Writer.Write("if ("); + if (member.ParamsReadSource != null) + { + Writer.Write("!"); + Writer.Write(member.ParamsReadSource); + Writer.Write(" && "); + } + if (checkType) + { + if (e.Mapping is NullableMapping) + { + TypeDesc td = ((NullableMapping)e.Mapping).BaseMapping.TypeDesc; + Writer.Write(RaCodeGen.GetStringForTypeof(td.CSharpName, td.UseReflection)); + } + else + { + Writer.Write(RaCodeGen.GetStringForTypeof(e.Mapping.TypeDesc.CSharpName, e.Mapping.TypeDesc.UseReflection)); + } + Writer.Write(".IsAssignableFrom("); + Writer.Write(checkTypeSource); + Writer.Write("Type)"); + } + else + { + if (member.Mapping.IsReturnValue) + Writer.Write("(IsReturnValue || "); + if (isSequence && e.Any && e.AnyNamespaces == null) + { + Writer.Write("true"); + } + else + { + WriteXmlNodeEqual("Reader", e.Name, ns); + } + if (member.Mapping.IsReturnValue) + Writer.Write(")"); + } + Writer.WriteLine(") {"); + Writer.Indent++; + if (checkType) + { + if (e.Mapping.TypeDesc.IsValueType || e.Mapping is NullableMapping) + { + Writer.Write("if ("); + Writer.Write(checkTypeSource); + Writer.WriteLine(" != null) {"); + Writer.Indent++; + } + if (e.Mapping is NullableMapping) + { + WriteSourceBegin(member.ArraySource); + TypeDesc td = ((NullableMapping)e.Mapping).BaseMapping.TypeDesc; + Writer.Write(RaCodeGen.GetStringForCreateInstance(e.Mapping.TypeDesc.CSharpName, e.Mapping.TypeDesc.UseReflection, false, true, "(" + td.CSharpName + ")" + checkTypeSource)); + } + else + { + WriteSourceBeginTyped(member.ArraySource, e.Mapping.TypeDesc); + Writer.Write(checkTypeSource); + } + WriteSourceEnd(member.ArraySource); + Writer.WriteLine(";"); + if (e.Mapping.TypeDesc.IsValueType) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + if (member.FixupIndex >= 0) + { + Writer.Write("fixup.Ids["); + Writer.Write(member.FixupIndex.ToString(CultureInfo.InvariantCulture)); + Writer.Write("] = "); + Writer.Write(checkTypeSource); + Writer.WriteLine("Id;"); + } + } + else + { + 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) + Writer.WriteLine("IsReturnValue = false;"); + if (member.ParamsReadSource != null) + { + Writer.Write(member.ParamsReadSource); + Writer.WriteLine(" = true;"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + if (isSequence) + { + if (member.IsArrayLike) + { + Writer.WriteLine("else {"); + Writer.Indent++; + } + cases++; + Writer.Write("state = "); + Writer.Write(cases.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine(";"); + if (member.IsArrayLike) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.WriteLine("break;"); + Writer.Indent--; + } + } + if (count > 0) + { + if (isSequence) + Writer.WriteLine("default:"); + else + Writer.WriteLine("else {"); + Writer.Indent++; + } + WriteMemberElementsElse(anyElement, elementElseString); + if (count > 0) + { + if (isSequence) + { + Writer.WriteLine("break;"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + private string GetArraySource(TypeDesc typeDesc, string arrayName) + { + return GetArraySource(typeDesc, arrayName, false); + } + private 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)); "; + } + bool useReflection = typeDesc.UseReflection; + if (typeDesc.IsArray) + { + string arrayTypeFullName = typeDesc.ArrayElementTypeDesc.CSharpName; + bool arrayUseReflection = typeDesc.ArrayElementTypeDesc.UseReflection; + string castString = useReflection ? "" : "(" + arrayTypeFullName + "[])"; + init = init + a + " = " + castString + + "EnsureArrayIndex(" + a + ", " + c + ", " + RaCodeGen.GetStringForTypeof(arrayTypeFullName, arrayUseReflection) + ");"; + 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", useReflection); + } + } + + + private void WriteMemberEnd(Member[] members) + { + WriteMemberEnd(members, false); + } + + private 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); + + if (soapRefs) + Writer.Write(" soap[1] = "); + + string a = member.ArrayName; + string c = "c" + a; + + bool arrayUseReflection = typeDesc.ArrayElementTypeDesc.UseReflection; + string arrayTypeFullName = typeDesc.ArrayElementTypeDesc.CSharpName; + if (!arrayUseReflection) + Writer.Write("(" + arrayTypeFullName + "[])"); + Writer.Write("ShrinkArray("); + Writer.Write(a); + Writer.Write(", "); + Writer.Write(c); + Writer.Write(", "); + Writer.Write(RaCodeGen.GetStringForTypeof(arrayTypeFullName, arrayUseReflection)); + Writer.Write(", "); + WriteBooleanValue(member.IsNullable); + Writer.Write(")"); + WriteSourceEnd(member.Source); + Writer.WriteLine(";"); + + if (member.Mapping.ChoiceIdentifier != null) + { + WriteSourceBegin(member.ChoiceSource); + a = member.ChoiceArrayName; + c = "c" + a; + + bool choiceUseReflection = member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.UseReflection; + string choiceTypeName = member.Mapping.ChoiceIdentifier.Mapping.TypeDesc.CSharpName; + if (!choiceUseReflection) + Writer.Write("(" + choiceTypeName + "[])"); + Writer.Write("ShrinkArray("); + Writer.Write(a); + Writer.Write(", "); + Writer.Write(c); + Writer.Write(", "); + Writer.Write(RaCodeGen.GetStringForTypeof(choiceTypeName, choiceUseReflection)); + Writer.Write(", "); + WriteBooleanValue(member.IsNullable); + Writer.Write(")"); + WriteSourceEnd(member.ChoiceSource); + Writer.WriteLine(";"); + } + } + else if (typeDesc.IsValueType) + { + Writer.Write(member.Source); + Writer.Write(" = "); + Writer.Write(member.ArrayName); + Writer.WriteLine(";"); + } + } + } + } + + private void WriteSourceBeginTyped(string source, TypeDesc typeDesc) + { + WriteSourceBegin(source); + if (typeDesc != null && !typeDesc.UseReflection) + { + Writer.Write("("); + Writer.Write(typeDesc.CSharpName); + Writer.Write(")"); + } + } + + private void WriteSourceBegin(string source) + { + Writer.Write(source); + if (source[source.Length - 1] != '(' && source[source.Length - 1] != '{') + Writer.Write(" = "); + } + + private void WriteSourceEnd(string source) + { + // source could be of the form "var", "arrayVar[i]", + // "collection.Add(" or "methodInfo.Invoke(collection, new object[] {" + if (source[source.Length - 1] == '(') + Writer.Write(")"); + else if (source[source.Length - 1] == '{') + Writer.Write("})"); + } + + private void WriteArray(string source, string arrayName, ArrayMapping arrayMapping, bool readOnly, bool isNullable, int fixupIndex) + { + if (arrayMapping.IsSoap) + { + Writer.Write("object rre = "); + Writer.Write(fixupIndex >= 0 ? "ReadReferencingElement" : "ReadReferencedElement"); + Writer.Write("("); + WriteID(arrayMapping.TypeName); + Writer.Write(", "); + WriteID(arrayMapping.Namespace); + if (fixupIndex >= 0) + { + Writer.Write(", "); + Writer.Write("out fixup.Ids["); + Writer.Write((fixupIndex).ToString(CultureInfo.InvariantCulture)); + Writer.Write("]"); + } + Writer.WriteLine(");"); + + TypeDesc td = arrayMapping.TypeDesc; + if (td.IsEnumerable || td.IsCollection) + { + Writer.WriteLine("if (rre != null) {"); + Writer.Indent++; + WriteAddCollectionFixup(td, readOnly, source, "rre"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + Writer.WriteLine("try {"); + Writer.Indent++; + WriteSourceBeginTyped(source, arrayMapping.TypeDesc); + Writer.Write("rre"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + WriteCatchCastException(arrayMapping.TypeDesc, "rre", null); + } + } + else + { + Writer.WriteLine("if (!ReadNull()) {"); + Writer.Indent++; + + MemberMapping memberMapping = new MemberMapping(); + memberMapping.Elements = arrayMapping.Elements; + memberMapping.TypeDesc = arrayMapping.TypeDesc; + memberMapping.ReadOnly = readOnly; + Member member = new Member(this, source, arrayName, 0, memberMapping, false); + member.IsNullable = false;//Note, sowmys: IsNullable is set to false since null condition (xsi:nil) is already handled by 'ReadNull()' + + Member[] members = new Member[] { member }; + WriteMemberBegin(members); + + if (readOnly) + { + Writer.Write("if (((object)("); + Writer.Write(member.ArrayName); + Writer.Write(") == null) || "); + } + else + { + Writer.Write("if ("); + } + Writer.WriteLine("(Reader.IsEmptyElement)) {"); + Writer.Indent++; + Writer.WriteLine("Reader.Skip();"); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else {"); + Writer.Indent++; + + Writer.WriteLine("Reader.ReadStartElement();"); + int loopIndex = WriteWhileNotLoopStart(); + Writer.Indent++; + + string unknownNode = "UnknownNode(null, " + ExpectedElements(members) + ");"; + WriteMemberElements(members, unknownNode, unknownNode, null, null, null); + Writer.WriteLine("Reader.MoveToContent();"); + + WriteWhileLoopEnd(loopIndex); + Writer.Indent--; + Writer.WriteLine("ReadEndElement();"); + Writer.WriteLine("}"); + + WriteMemberEnd(members, false); + + Writer.Indent--; + Writer.WriteLine("}"); + if (isNullable) + { + Writer.WriteLine("else {"); + Writer.Indent++; + member.IsNullable = true; + WriteMemberBegin(members); + WriteMemberEnd(members); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + } + + private 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) + { + Writer.Write(checkSpecified); + Writer.WriteLine(" = true;"); + } + + if (element.Mapping is ArrayMapping) + { + WriteArray(source, arrayName, (ArrayMapping)element.Mapping, readOnly, element.IsNullable, fixupIndex); + } + 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(SR.Format(SR.XmlInternalErrorMethod, element.Mapping.TypeDesc.Name)); +#endif + WriteSourceBegin(source); + Writer.Write(methodName); + Writer.Write("(true)"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + } + else if (!element.Mapping.IsSoap && (element.Mapping is PrimitiveMapping)) + { + if (element.IsNullable) + { + Writer.WriteLine("if (ReadNull()) {"); + Writer.Indent++; + WriteSourceBegin(source); + if (element.Mapping.TypeDesc.IsValueType) + { + Writer.Write(RaCodeGen.GetStringForCreateInstance(element.Mapping.TypeDesc.CSharpName, element.Mapping.TypeDesc.UseReflection, false, false)); + } + else + { + Writer.Write("null"); + } + WriteSourceEnd(source); + Writer.WriteLine(";"); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.Write("else "); + } + if (element.Default != null && element.Default != DBNull.Value && element.Mapping.TypeDesc.IsValueType) + { + Writer.WriteLine("if (Reader.IsEmptyElement) {"); + Writer.Indent++; + Writer.WriteLine("Reader.Skip();"); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else {"); + } + else + { + Writer.WriteLine("{"); + } + Writer.Indent++; + + WriteSourceBegin(source); + if (element.Mapping.TypeDesc == QnameTypeDesc) + Writer.Write("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); + Writer.WriteLine(";"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else if (element.Mapping is StructMapping || (element.Mapping.IsSoap && element.Mapping is PrimitiveMapping)) + { + TypeMapping mapping = element.Mapping; + if (mapping.IsSoap) + { + Writer.Write("object rre = "); + Writer.Write(fixupIndex >= 0 ? "ReadReferencingElement" : "ReadReferencedElement"); + Writer.Write("("); + WriteID(mapping.TypeName); + Writer.Write(", "); + WriteID(mapping.Namespace); + + if (fixupIndex >= 0) + { + Writer.Write(", out fixup.Ids["); + Writer.Write((fixupIndex).ToString(CultureInfo.InvariantCulture)); + Writer.Write("]"); + } + Writer.Write(")"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + + if (mapping.TypeDesc.IsValueType) + { + Writer.WriteLine("if (rre != null) {"); + Writer.Indent++; + } + + Writer.WriteLine("try {"); + Writer.Indent++; + WriteSourceBeginTyped(source, mapping.TypeDesc); + Writer.Write("rre"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + WriteCatchCastException(mapping.TypeDesc, "rre", null); + Writer.Write("Referenced("); + Writer.Write(source); + Writer.WriteLine(");"); + if (mapping.TypeDesc.IsValueType) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + } + else + { + 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 + + if (checkForNull) + { + Writer.Write("if ((object)("); + Writer.Write(arrayName); + Writer.Write(") == null) Reader.Skip(); else "); + } + WriteSourceBegin(source); + Writer.Write(methodName); + Writer.Write("("); + if (mapping.TypeDesc.IsNullable) + { + WriteBooleanValue(element.IsNullable); + Writer.Write(", "); + } + Writer.Write("true"); + Writer.Write(")"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + } + } + 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); + Writer.Write(isDoc ? "ReadXmlDocument(" : "ReadXmlNode("); + Writer.Write(element.Any ? "false" : "true"); + Writer.Write(")"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + break; + case TypeKind.Serializable: + SerializableMapping sm = (SerializableMapping)element.Mapping; + // check to see if we need to do the derivation + if (sm.DerivedMappings != null) + { + Writer.Write(typeof(XmlQualifiedName).FullName); + Writer.WriteLine(" tser = GetXsiType();"); + Writer.Write("if (tser == null"); + Writer.Write(" || "); + WriteQNameEqual("tser", sm.XsiType.Name, sm.XsiType.Namespace); + + Writer.WriteLine(") {"); + Writer.Indent++; + } + WriteSourceBeginTyped(source, sm.TypeDesc); + Writer.Write("ReadSerializable(( "); + Writer.Write(typeof(IXmlSerializable).FullName); + Writer.Write(")"); + Writer.Write(RaCodeGen.GetStringForCreateInstance(sm.TypeDesc.CSharpName, sm.TypeDesc.UseReflection, sm.TypeDesc.CannotNew, false)); + bool isWrappedAny = !element.Any && IsWildcard(sm); + if (isWrappedAny) + { + Writer.WriteLine(", true"); + } + Writer.Write(")"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + if (sm.DerivedMappings != null) + { + Writer.Indent--; + Writer.WriteLine("}"); + WriteDerivedSerializable(sm, sm, source, isWrappedAny); + WriteUnknownNode("UnknownNode", "null", null, true); + } + break; + default: + throw new InvalidOperationException(SR.XmlInternalError); + } + } + else + { + throw new InvalidOperationException(SR.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(SR.Format(SR.XmlInternalErrorDetails, "need parent for the " + source)); +#endif + + string enumTypeName = choice.Mapping.TypeDesc.CSharpName; + Writer.Write(choiceSource); + Writer.Write(" = "); + CodeIdentifier.CheckValidIdentifier(choice.MemberIds[elementIndex]); + Writer.Write(RaCodeGen.GetStringForEnumMember(enumTypeName, choice.MemberIds[elementIndex], choice.Mapping.TypeDesc.UseReflection)); + Writer.WriteLine(";"); + } + } + + private void WriteDerivedSerializable(SerializableMapping head, SerializableMapping mapping, string source, bool isWrappedAny) + { + if (mapping == null) + return; + for (SerializableMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) + { + Writer.Write("else if (tser == null"); + Writer.Write(" || "); + WriteQNameEqual("tser", derived.XsiType.Name, derived.XsiType.Namespace); + + Writer.WriteLine(") {"); + Writer.Indent++; + + if (derived.Type != null) + { + if (head.Type.IsAssignableFrom(derived.Type)) + { + WriteSourceBeginTyped(source, head.TypeDesc); + Writer.Write("ReadSerializable(( "); + Writer.Write(typeof(IXmlSerializable).FullName); + Writer.Write(")"); + Writer.Write(RaCodeGen.GetStringForCreateInstance(derived.TypeDesc.CSharpName, derived.TypeDesc.UseReflection, derived.TypeDesc.CannotNew, false)); + if (isWrappedAny) + { + Writer.WriteLine(", true"); + } + Writer.Write(")"); + WriteSourceEnd(source); + Writer.WriteLine(";"); + } + else + { + Writer.Write("throw CreateBadDerivationException("); + WriteQuotedCSharpString(derived.XsiType.Name); + Writer.Write(", "); + WriteQuotedCSharpString(derived.XsiType.Namespace); + Writer.Write(", "); + WriteQuotedCSharpString(head.XsiType.Name); + Writer.Write(", "); + WriteQuotedCSharpString(head.XsiType.Namespace); + Writer.Write(", "); + WriteQuotedCSharpString(derived.Type.FullName); + Writer.Write(", "); + WriteQuotedCSharpString(head.Type.FullName); + Writer.WriteLine(");"); + } + } + else + { + Writer.WriteLine("// " + "missing real mapping for " + derived.XsiType); + Writer.Write("throw CreateMissingIXmlSerializableType("); + WriteQuotedCSharpString(derived.XsiType.Name); + Writer.Write(", "); + WriteQuotedCSharpString(derived.XsiType.Namespace); + Writer.Write(", "); + WriteQuotedCSharpString(head.Type.FullName); + Writer.WriteLine(");"); + } + + Writer.Indent--; + Writer.WriteLine("}"); + + WriteDerivedSerializable(head, derived, source, isWrappedAny); + } + } + + private int WriteWhileNotLoopStart() + { + Writer.WriteLine("Reader.MoveToContent();"); + int loopIndex = WriteWhileLoopStartCheck(); + Writer.Write("while (Reader.NodeType != "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.Write(".EndElement && Reader.NodeType != "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".None) {"); + return loopIndex; + } + + private void WriteWhileLoopEnd(int loopIndex) + { + WriteWhileLoopEndCheck(loopIndex); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private int WriteWhileLoopStartCheck() + { + Writer.WriteLine(String.Format(CultureInfo.InvariantCulture, "int whileIterations{0} = 0;", _nextWhileLoopIndex)); + Writer.WriteLine(String.Format(CultureInfo.InvariantCulture, "int readerCount{0} = ReaderCount;", _nextWhileLoopIndex)); + return _nextWhileLoopIndex++; + } + + private void WriteWhileLoopEndCheck(int loopIndex) + { + Writer.WriteLine(String.Format(CultureInfo.InvariantCulture, "CheckReaderCount(ref whileIterations{0}, ref readerCount{1});", loopIndex, loopIndex)); + } + + private void WriteParamsRead(int length) + { + Writer.Write("bool[] paramsRead = new bool["); + Writer.Write(length.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine("];"); + } + + private void WriteReadNonRoots() + { + Writer.WriteLine("Reader.MoveToContent();"); + int loopIndex = WriteWhileLoopStartCheck(); + Writer.Write("while (Reader.NodeType == "); + Writer.Write(typeof(XmlNodeType).FullName); + Writer.WriteLine(".Element) {"); + Writer.Indent++; + Writer.Write("string root = Reader.GetAttribute(\"root\", \""); + Writer.Write(Soap.Encoding); + Writer.WriteLine("\");"); + Writer.Write("if (root == null || "); + Writer.Write(typeof(XmlConvert).FullName); + Writer.WriteLine(".ToBoolean(root)) break;"); + Writer.WriteLine("ReadReferencedElement();"); + Writer.WriteLine("Reader.MoveToContent();"); + WriteWhileLoopEnd(loopIndex); + } + + private void WriteBooleanValue(bool value) + { + Writer.Write(value ? "true" : "false"); + } + + private void WriteInitCheckTypeHrefList(string source) + { + Writer.Write(typeof(ArrayList).FullName); + Writer.Write(" "); + Writer.Write(source); + Writer.Write(" = new "); + Writer.Write(typeof(ArrayList).FullName); + Writer.WriteLine("();"); + + Writer.Write(typeof(ArrayList).FullName); + Writer.Write(" "); + Writer.Write(source); + Writer.Write("IsObject = new "); + Writer.Write(typeof(ArrayList).FullName); + Writer.WriteLine("();"); + } + + private void WriteHandleHrefList(Member[] members, string listSource) + { + Writer.WriteLine("int isObjectIndex = 0;"); + Writer.Write("foreach (object obj in "); + Writer.Write(listSource); + Writer.WriteLine(") {"); + Writer.Indent++; + Writer.WriteLine("bool isReferenced = true;"); + Writer.Write("bool isObject = (bool)"); + Writer.Write(listSource); + Writer.WriteLine("IsObject[isObjectIndex++];"); + Writer.WriteLine("object refObj = isObject ? obj : GetTarget((string)obj);"); + Writer.WriteLine("if (refObj == null) continue;"); + Writer.Write(typeof(Type).FullName); + Writer.WriteLine(" refObjType = refObj.GetType();"); + Writer.WriteLine("string refObjId = null;"); + + WriteMemberElementsIf(members, null, "isReferenced = false;", "refObj"); + + Writer.WriteLine("if (isObject && isReferenced) Referenced(refObj); // need to mark this obj as ref'd since we didn't do GetTarget"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteIfNotSoapRoot(string source) + { + Writer.Write("if (Reader.GetAttribute(\"root\", \""); + Writer.Write(Soap.Encoding); + Writer.WriteLine("\") == \"0\") {"); + Writer.Indent++; + Writer.WriteLine(source); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteCreateMapping(TypeMapping mapping, string local) + { + string fullTypeName = mapping.TypeDesc.CSharpName; + bool useReflection = mapping.TypeDesc.UseReflection; + bool ctorInaccessible = mapping.TypeDesc.CannotNew; + + Writer.Write(useReflection ? "object" : fullTypeName); + Writer.Write(" "); + Writer.Write(local); + Writer.WriteLine(";"); + + if (ctorInaccessible) + { + Writer.WriteLine("try {"); + Writer.Indent++; + } + Writer.Write(local); + Writer.Write(" = "); + Writer.Write(RaCodeGen.GetStringForCreateInstance(fullTypeName, useReflection, mapping.TypeDesc.CannotNew, true)); + Writer.WriteLine(";"); + if (ctorInaccessible) + { + WriteCatchException(typeof(MissingMethodException)); + Writer.Indent++; + Writer.Write("throw CreateInaccessibleConstructorException("); + WriteQuotedCSharpString(fullTypeName); + Writer.WriteLine(");"); + + WriteCatchException(typeof(SecurityException)); + Writer.Indent++; + + Writer.Write("throw CreateCtorHasSecurityException("); + WriteQuotedCSharpString(fullTypeName); + Writer.WriteLine(");"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + private void WriteCatchException(Type exceptionType) + { + Writer.Indent--; + Writer.WriteLine("}"); + Writer.Write("catch ("); + Writer.Write(exceptionType.FullName); + Writer.WriteLine(") {"); + } + + private void WriteCatchCastException(TypeDesc typeDesc, string source, string id) + { + WriteCatchException(typeof(InvalidCastException)); + Writer.Indent++; + Writer.Write("throw CreateInvalidCastException("); + Writer.Write(RaCodeGen.GetStringForTypeof(typeDesc.CSharpName, typeDesc.UseReflection)); + Writer.Write(", "); + Writer.Write(source); + if (id == null) + Writer.WriteLine(", null);"); + else + { + Writer.Write(", (string)"); + Writer.Write(id); + Writer.WriteLine(");"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + private void WriteArrayLocalDecl(string typeName, string variableName, string initValue, TypeDesc arrayTypeDesc) + { + RaCodeGen.WriteArrayLocalDecl(typeName, variableName, initValue, arrayTypeDesc); + } + private void WriteCreateInstance(string escapedName, string source, bool useReflection, bool ctorInaccessible) + { + RaCodeGen.WriteCreateInstance(escapedName, source, useReflection, ctorInaccessible); + } + private void WriteLocalDecl(string typeFullName, string variableName, string initValue, bool useReflection) + { + RaCodeGen.WriteLocalDecl(typeFullName, variableName, initValue, useReflection); + } + } #endif } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs index ef0541fe1d..c28af8e265 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.IO; @@ -25,11 +21,7 @@ namespace System.Xml.Serialization using System.Xml; ///<internalonly/> -#if XMLSERIALIZERGENERATOR - internal abstract class XmlSerializationWriter : XmlSerializationGeneratedCode -#else public abstract class XmlSerializationWriter : XmlSerializationGeneratedCode -#endif { private XmlWriter _w; private XmlSerializerNamespaces _namespaces; @@ -1444,11 +1436,7 @@ namespace System.Xml.Serialization ///<internalonly/> -#if XMLSERIALIZERGENERATOR - internal delegate void XmlSerializationWriteCallback(object o); -#else public delegate void XmlSerializationWriteCallback(object o); -#endif internal static class DynamicAssemblies @@ -1496,7 +1484,7 @@ namespace System.Xml.Serialization return (bool)oIsTypeDynamic; } -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT internal static bool IsTypeDynamic(Type[] arguments) { foreach (Type t in arguments) @@ -1543,7 +1531,7 @@ namespace System.Xml.Serialization return s_nameToAssemblyMap != null ? (Assembly)s_nameToAssemblyMap[fullName] : null; } -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT internal static string GetName(Assembly a) { return s_assemblyToNameMap != null ? (string) s_assemblyToNameMap[a] : null; @@ -1551,7 +1539,7 @@ namespace System.Xml.Serialization #endif } -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT internal class ReflectionAwareCodeGen { private const string hexDigits = "0123456789ABCDEF"; @@ -2205,5 +2193,2213 @@ namespace System.Xml.Serialization }} "; } + + internal class XmlSerializationWriterCodeGen : XmlSerializationCodeGen + { + internal XmlSerializationWriterCodeGen(IndentedWriter writer, TypeScope[] scopes, string access, string className) : base(writer, scopes, access, className) + { + } + + internal void GenerateBegin() + { + Writer.Write(Access); + Writer.Write(" class "); + Writer.Write(ClassName); + Writer.Write(" : "); + Writer.Write(typeof(System.Xml.Serialization.XmlSerializationWriter).FullName); + Writer.WriteLine(" {"); + Writer.Indent++; + + foreach (TypeScope scope in Scopes) + { + foreach (TypeMapping mapping in scope.TypeMappings) + { + if (mapping is StructMapping || mapping is EnumMapping) + { + MethodNames.Add(mapping, NextMethodName(mapping.TypeDesc.Name)); + } + } + RaCodeGen.WriteReflectionInit(scope); + } + + // pre-generate write methods only for the encoded soap + foreach (TypeScope scope in Scopes) + { + foreach (TypeMapping mapping in scope.TypeMappings) + { + if (!mapping.IsSoap) + continue; + + if (mapping is StructMapping) + WriteStructMethod((StructMapping)mapping); + else if (mapping is EnumMapping) + WriteEnumMethod((EnumMapping)mapping); + } + } + } + + 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); + } + } + internal void GenerateEnd() + { + GenerateReferencedMethods(); + GenerateInitCallbacksMethod(); + Writer.Indent--; + Writer.WriteLine("}"); + } + + internal string GenerateElement(XmlMapping xmlMapping) + { + if (!xmlMapping.IsWriteable) + return null; + if (!xmlMapping.GenerateSerializer) + throw new ArgumentException(SR.XmlInternalError, nameof(xmlMapping)); + if (xmlMapping is XmlTypeMapping) + return GenerateTypeElement((XmlTypeMapping)xmlMapping); + else if (xmlMapping is XmlMembersMapping) + return GenerateMembersElement((XmlMembersMapping)xmlMapping); + else + throw new ArgumentException(SR.XmlInternalError, nameof(xmlMapping)); + } + + private void GenerateInitCallbacksMethod() + { + Writer.WriteLine(); + Writer.WriteLine("protected override void InitCallbacks() {"); + Writer.Indent++; + + foreach (TypeScope scope in Scopes) + { + foreach (TypeMapping typeMapping in scope.TypeMappings) + { + if (typeMapping.IsSoap && + (typeMapping is StructMapping || typeMapping is EnumMapping) && + !typeMapping.TypeDesc.IsRoot) + { + string methodName = (string)MethodNames[typeMapping]; + Writer.Write("AddWriteCallback("); + Writer.Write(RaCodeGen.GetStringForTypeof(typeMapping.TypeDesc.CSharpName, typeMapping.TypeDesc.UseReflection)); + Writer.Write(", "); + WriteQuotedCSharpString(typeMapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(typeMapping.Namespace); + Writer.Write(", new "); + Writer.Write(typeof(System.Xml.Serialization.XmlSerializationWriteCallback).FullName); + Writer.Write("(this."); + Writer.Write(methodName); + Writer.WriteLine("));"); + } + } + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteQualifiedNameElement(string name, string ns, object defaultValue, string source, bool nullable, bool IsSoap, TypeMapping mapping) + { + bool hasDefault = defaultValue != null && defaultValue != DBNull.Value; + if (hasDefault) + { + WriteCheckDefault(mapping, source, defaultValue, nullable); + Writer.WriteLine(" {"); + Writer.Indent++; + } + string suffix = IsSoap ? "Encoded" : "Literal"; + Writer.Write(nullable ? ("WriteNullableQualifiedName" + suffix) : "WriteElementQualifiedName"); + Writer.Write("("); + WriteQuotedCSharpString(name); + if (ns != null) + { + Writer.Write(", "); + WriteQuotedCSharpString(ns); + } + Writer.Write(", "); + Writer.Write(source); + + if (IsSoap) + { + Writer.Write(", new System.Xml.XmlQualifiedName("); + WriteQuotedCSharpString(mapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(mapping.Namespace); + Writer.Write(")"); + } + + Writer.WriteLine(");"); + + if (hasDefault) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + private void WriteEnumValue(EnumMapping mapping, string source) + { + 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) + Environment.StackTrace); +#endif + + Writer.Write(methodName); + Writer.Write("("); + Writer.Write(source); + Writer.Write(")"); + } + + private void WritePrimitiveValue(TypeDesc typeDesc, string source, bool isElement) + { + if (typeDesc == StringTypeDesc || typeDesc.FormatterName == "String") + { + Writer.Write(source); + } + else + { + if (!typeDesc.HasCustomFormatter) + { + Writer.Write(typeof(XmlConvert).FullName); + Writer.Write(".ToString(("); + Writer.Write(typeDesc.CSharpName); + Writer.Write(")"); + Writer.Write(source); + Writer.Write(")"); + } + else + { + Writer.Write("From"); + Writer.Write(typeDesc.FormatterName); + Writer.Write("("); + Writer.Write(source); + Writer.Write(")"); + } + } + } + + private void WritePrimitive(string method, string name, string ns, object defaultValue, string source, TypeMapping mapping, bool writeXsiType, bool isElement, bool isNullable) + { + TypeDesc typeDesc = mapping.TypeDesc; + bool hasDefault = defaultValue != null && defaultValue != DBNull.Value && mapping.TypeDesc.HasDefaultSupport; + if (hasDefault) + { + if (mapping is EnumMapping) + { +#if DEBUG + // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe + if (defaultValue.GetType() != typeof(string)) throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, name + " has invalid default type " + defaultValue.GetType().Name)); +#endif + + Writer.Write("if ("); + if (mapping.TypeDesc.UseReflection) + Writer.Write(RaCodeGen.GetStringForEnumLongValue(source, mapping.TypeDesc.UseReflection)); + else + Writer.Write(source); + Writer.Write(" != "); + if (((EnumMapping)mapping).IsFlags) + { + Writer.Write("("); + string[] values = ((string)defaultValue).Split(null); + for (int i = 0; i < values.Length; i++) + { + if (values[i] == null || values[i].Length == 0) + continue; + if (i > 0) + Writer.WriteLine(" | "); + Writer.Write(RaCodeGen.GetStringForEnumCompare((EnumMapping)mapping, values[i], mapping.TypeDesc.UseReflection)); + } + Writer.Write(")"); + } + else + { + Writer.Write(RaCodeGen.GetStringForEnumCompare((EnumMapping)mapping, (string)defaultValue, mapping.TypeDesc.UseReflection)); + } + Writer.Write(")"); + } + else + { + WriteCheckDefault(mapping, source, defaultValue, isNullable); + } + Writer.WriteLine(" {"); + Writer.Indent++; + } + Writer.Write(method); + Writer.Write("("); + WriteQuotedCSharpString(name); + if (ns != null) + { + Writer.Write(", "); + WriteQuotedCSharpString(ns); + } + Writer.Write(", "); + + if (mapping is EnumMapping) + { + WriteEnumValue((EnumMapping)mapping, source); + } + else + { + WritePrimitiveValue(typeDesc, source, isElement); + } + + if (writeXsiType) + { + Writer.Write(", new System.Xml.XmlQualifiedName("); + WriteQuotedCSharpString(mapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(mapping.Namespace); + Writer.Write(")"); + } + + Writer.WriteLine(");"); + + if (hasDefault) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + private void WriteTag(string methodName, string name, string ns) + { + Writer.Write(methodName); + Writer.Write("("); + WriteQuotedCSharpString(name); + Writer.Write(", "); + if (ns == null) + { + Writer.Write("null"); + } + else + { + WriteQuotedCSharpString(ns); + } + Writer.WriteLine(");"); + } + + private void WriteTag(string methodName, string name, string ns, bool writePrefixed) + { + Writer.Write(methodName); + Writer.Write("("); + WriteQuotedCSharpString(name); + Writer.Write(", "); + if (ns == null) + { + Writer.Write("null"); + } + else + { + WriteQuotedCSharpString(ns); + } + Writer.Write(", null, "); + if (writePrefixed) + Writer.Write("true"); + else + Writer.Write("false"); + Writer.WriteLine(");"); + } + + private void WriteStartElement(string name, string ns, bool writePrefixed) + { + WriteTag("WriteStartElement", name, ns, writePrefixed); + } + + private void WriteEndElement() + { + Writer.WriteLine("WriteEndElement();"); + } + private void WriteEndElement(string source) + { + Writer.Write("WriteEndElement("); + Writer.Write(source); + Writer.WriteLine(");"); + } + + private void WriteEncodedNullTag(string name, string ns) + { + WriteTag("WriteNullTagEncoded", name, ns); + } + + private void WriteLiteralNullTag(string name, string ns) + { + WriteTag("WriteNullTagLiteral", name, ns); + } + + private void WriteEmptyTag(string name, string ns) + { + WriteTag("WriteEmptyTag", name, ns); + } + + private string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) + { + ElementAccessor element = xmlMembersMapping.Accessor; + MembersMapping mapping = (MembersMapping)element.Mapping; + bool hasWrapperElement = mapping.HasWrapperElement; + bool writeAccessors = mapping.WriteAccessors; + bool isRpc = xmlMembersMapping.IsSoap && writeAccessors; + string methodName = NextMethodName(element.Name); + Writer.WriteLine(); + Writer.Write("public void "); + Writer.Write(methodName); + Writer.WriteLine("(object[] p) {"); + Writer.Indent++; + + Writer.WriteLine("WriteStartDocument();"); + + if (!mapping.IsSoap) + { + Writer.WriteLine("TopLevelElement();"); + } + + // in the top-level method add check for the parameters length, + // because visual basic does not have a concept of an <out> parameter it uses <ByRef> instead + // so sometime we think that we have more parameters then supplied + Writer.WriteLine("int pLength = p.Length;"); + + if (hasWrapperElement) + { + WriteStartElement(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""), mapping.IsSoap); + + int xmlnsMember = FindXmlnsIndex(mapping.Members); + if (xmlnsMember >= 0) + { + MemberMapping member = mapping.Members[xmlnsMember]; + string source = "((" + typeof(System.Xml.Serialization.XmlSerializerNamespaces).FullName + ")p[" + xmlnsMember.ToString(CultureInfo.InvariantCulture) + "])"; + + Writer.Write("if (pLength > "); + Writer.Write(xmlnsMember.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine(") {"); + Writer.Indent++; + WriteNamespaces(source); + Writer.Indent--; + Writer.WriteLine("}"); + } + + for (int i = 0; i < mapping.Members.Length; i++) + { + MemberMapping member = mapping.Members[i]; + + if (member.Attribute != null && !member.Ignore) + { + string index = i.ToString(CultureInfo.InvariantCulture); + string source = "p[" + index + "]"; + + string specifiedSource = null; + int specifiedPosition = 0; + if (member.CheckSpecified != SpecifiedAccessor.None) + { + string memberNameSpecified = member.Name + "Specified"; + for (int j = 0; j < mapping.Members.Length; j++) + { + if (mapping.Members[j].Name == memberNameSpecified) + { + specifiedSource = "((bool) p[" + j.ToString(CultureInfo.InvariantCulture) + "])"; + specifiedPosition = j; + break; + } + } + } + + Writer.Write("if (pLength > "); + Writer.Write(index); + Writer.WriteLine(") {"); + Writer.Indent++; + + if (specifiedSource != null) + { + Writer.Write("if (pLength <= "); + Writer.Write(specifiedPosition.ToString(CultureInfo.InvariantCulture)); + Writer.Write(" || "); + Writer.Write(specifiedSource); + Writer.WriteLine(") {"); + Writer.Indent++; + } + + WriteMember(source, member.Attribute, member.TypeDesc, "p"); + + if (specifiedSource != null) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + + Writer.Indent--; + Writer.WriteLine("}"); + } + } + } + + for (int i = 0; i < mapping.Members.Length; i++) + { + MemberMapping member = mapping.Members[i]; + if (member.Xmlns != null) + continue; + if (member.Ignore) + continue; + + string specifiedSource = null; + int specifiedPosition = 0; + if (member.CheckSpecified != SpecifiedAccessor.None) + { + string memberNameSpecified = member.Name + "Specified"; + + for (int j = 0; j < mapping.Members.Length; j++) + { + if (mapping.Members[j].Name == memberNameSpecified) + { + specifiedSource = "((bool) p[" + j.ToString(CultureInfo.InvariantCulture) + "])"; + specifiedPosition = j; + break; + } + } + } + + string index = i.ToString(CultureInfo.InvariantCulture); + Writer.Write("if (pLength > "); + Writer.Write(index); + Writer.WriteLine(") {"); + Writer.Indent++; + + if (specifiedSource != null) + { + Writer.Write("if (pLength <= "); + Writer.Write(specifiedPosition.ToString(CultureInfo.InvariantCulture)); + Writer.Write(" || "); + Writer.Write(specifiedSource); + Writer.WriteLine(") {"); + Writer.Indent++; + } + + string source = "p[" + index + "]"; + string enumSource = null; + if (member.ChoiceIdentifier != null) + { + for (int j = 0; j < mapping.Members.Length; j++) + { + if (mapping.Members[j].Name == member.ChoiceIdentifier.MemberName) + { + if (member.ChoiceIdentifier.Mapping.TypeDesc.UseReflection) + enumSource = "p[" + j.ToString(CultureInfo.InvariantCulture) + "]"; + else + enumSource = "((" + mapping.Members[j].TypeDesc.CSharpName + ")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 (enumSource == null) throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, "Can not find " + member.ChoiceIdentifier.MemberName + " in the members mapping.")); +#endif + } + + if (isRpc && member.IsReturnValue && member.Elements.Length > 0) + { + Writer.Write("WriteRpcResult("); + WriteQuotedCSharpString(member.Elements[0].Name); + Writer.Write(", "); + WriteQuotedCSharpString(""); + Writer.WriteLine(");"); + } + + // override writeAccessors choice when we've written a wrapper element + WriteMember(source, enumSource, member.ElementsSortedByDerivation, member.Text, member.ChoiceIdentifier, member.TypeDesc, writeAccessors || hasWrapperElement); + + if (specifiedSource != null) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + + Writer.Indent--; + Writer.WriteLine("}"); + } + + if (hasWrapperElement) + { + WriteEndElement(); + } + if (element.IsSoap) + { + if (!hasWrapperElement && !writeAccessors) + { + // doc/bare case -- allow extra members + Writer.Write("if (pLength > "); + Writer.Write(mapping.Members.Length.ToString(CultureInfo.InvariantCulture)); + Writer.WriteLine(") {"); + Writer.Indent++; + + WriteExtraMembers(mapping.Members.Length.ToString(CultureInfo.InvariantCulture), "pLength"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.WriteLine("WriteReferencedElements();"); + } + Writer.Indent--; + Writer.WriteLine("}"); + return methodName; + } + + private string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) + { + ElementAccessor element = xmlTypeMapping.Accessor; + TypeMapping mapping = element.Mapping; + string methodName = NextMethodName(element.Name); + Writer.WriteLine(); + Writer.Write("public void "); + Writer.Write(methodName); + Writer.WriteLine("(object o) {"); + Writer.Indent++; + + Writer.WriteLine("WriteStartDocument();"); + + Writer.WriteLine("if (o == null) {"); + Writer.Indent++; + if (element.IsNullable) + { + if (mapping.IsSoap) + WriteEncodedNullTag(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : "")); + else + WriteLiteralNullTag(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : "")); + } + else + WriteEmptyTag(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : "")); + Writer.WriteLine("return;"); + Writer.Indent--; + Writer.WriteLine("}"); + + if (!mapping.IsSoap && !mapping.TypeDesc.IsValueType && !mapping.TypeDesc.Type.IsPrimitive) + { + Writer.WriteLine("TopLevelElement();"); + } + + WriteMember("o", null, new ElementAccessor[] { element }, null, null, mapping.TypeDesc, !element.IsSoap); + + if (mapping.IsSoap) + { + Writer.WriteLine("WriteReferencedElements();"); + } + Writer.Indent--; + Writer.WriteLine("}"); + return methodName; + } + + private string NextMethodName(string name) + { + return "Write" + (++NextMethodNumber).ToString(null, NumberFormatInfo.InvariantInfo) + "_" + CodeIdentifier.MakeValidInternal(name); + } + + private void WriteEnumMethod(EnumMapping mapping) + { + string methodName = (string)MethodNames[mapping]; + Writer.WriteLine(); + string fullTypeName = mapping.TypeDesc.CSharpName; + if (mapping.IsSoap) + { + Writer.Write("void "); + Writer.Write(methodName); + Writer.WriteLine("(object e) {"); + WriteLocalDecl(fullTypeName, "v", "e", mapping.TypeDesc.UseReflection); + } + else + { + Writer.Write("string "); + Writer.Write(methodName); + Writer.Write("("); + Writer.Write(mapping.TypeDesc.UseReflection ? "object" : fullTypeName); + Writer.WriteLine(" v) {"); + } + Writer.Indent++; + Writer.WriteLine("string s = null;"); + ConstantMapping[] constants = mapping.Constants; + + if (constants.Length > 0) + { + Hashtable values = new Hashtable(); + if (mapping.TypeDesc.UseReflection) + Writer.WriteLine("switch (" + RaCodeGen.GetStringForEnumLongValue("v", mapping.TypeDesc.UseReflection) + " ){"); + else + Writer.WriteLine("switch (v) {"); + Writer.Indent++; + for (int i = 0; i < constants.Length; i++) + { + ConstantMapping c = constants[i]; + if (values[c.Value] == null) + { + WriteEnumCase(fullTypeName, c, mapping.TypeDesc.UseReflection); + Writer.Write("s = "); + WriteQuotedCSharpString(c.XmlName); + Writer.WriteLine("; break;"); + values.Add(c.Value, c.Value); + } + } + + + if (mapping.IsFlags) + { + Writer.Write("default: s = FromEnum("); + Writer.Write(RaCodeGen.GetStringForEnumLongValue("v", mapping.TypeDesc.UseReflection)); + Writer.Write(", new string[] {"); + Writer.Indent++; + for (int i = 0; i < constants.Length; i++) + { + ConstantMapping c = constants[i]; + if (i > 0) + Writer.WriteLine(", "); + WriteQuotedCSharpString(c.XmlName); + } + Writer.Write("}, new "); + Writer.Write(typeof(long).FullName); + Writer.Write("[] {"); + + for (int i = 0; i < constants.Length; i++) + { + ConstantMapping c = constants[i]; + if (i > 0) + Writer.WriteLine(", "); + Writer.Write("(long)"); + if (mapping.TypeDesc.UseReflection) + Writer.Write(c.Value.ToString(CultureInfo.InvariantCulture)); + else + { + Writer.Write(fullTypeName); + Writer.Write(".@"); + CodeIdentifier.CheckValidIdentifier(c.Name); + Writer.Write(c.Name); + } + } + Writer.Indent--; + Writer.Write("}, "); + WriteQuotedCSharpString(mapping.TypeDesc.FullName); + Writer.WriteLine("); break;"); + } + else + { + Writer.Write("default: throw CreateInvalidEnumValueException("); + Writer.Write(RaCodeGen.GetStringForEnumLongValue("v", mapping.TypeDesc.UseReflection)); + Writer.Write(".ToString(System.Globalization.CultureInfo.InvariantCulture), "); + WriteQuotedCSharpString(mapping.TypeDesc.FullName); + Writer.WriteLine(");"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + if (mapping.IsSoap) + { + Writer.Write("WriteXsiType("); + WriteQuotedCSharpString(mapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(mapping.Namespace); + Writer.WriteLine(");"); + Writer.WriteLine("Writer.WriteString(s);"); + } + else + { + Writer.WriteLine("return s;"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteDerivedTypes(StructMapping mapping) + { + for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) + { + string fullTypeName = derived.TypeDesc.CSharpName; + Writer.Write("else if ("); + WriteTypeCompare("t", fullTypeName, derived.TypeDesc.UseReflection); + Writer.WriteLine(") {"); + Writer.Indent++; + + 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("derived from " + mapping.TypeDesc.FullName + ", " + SR.Format(SR.XmlInternalErrorMethod, derived.TypeDesc.Name) + Environment.StackTrace); +#endif + + Writer.Write(methodName); + Writer.Write("(n, ns,"); + if (!derived.TypeDesc.UseReflection) Writer.Write("(" + fullTypeName + ")"); + Writer.Write("o"); + if (derived.TypeDesc.IsNullable) + Writer.Write(", isNullable"); + Writer.Write(", true"); + Writer.WriteLine(");"); + Writer.WriteLine("return;"); + Writer.Indent--; + Writer.WriteLine("}"); + + WriteDerivedTypes(derived); + } + } + + private void WriteEnumAndArrayTypes() + { + foreach (TypeScope scope in Scopes) + { + foreach (Mapping m in scope.TypeMappings) + { + if (m is EnumMapping && !m.IsSoap) + { + EnumMapping mapping = (EnumMapping)m; + string fullTypeName = mapping.TypeDesc.CSharpName; + Writer.Write("else if ("); + WriteTypeCompare("t", fullTypeName, mapping.TypeDesc.UseReflection); + Writer.WriteLine(") {"); + Writer.Indent++; + + 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) + Environment.StackTrace); +#endif + Writer.WriteLine("Writer.WriteStartElement(n, ns);"); + Writer.Write("WriteXsiType("); + WriteQuotedCSharpString(mapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(mapping.Namespace); + Writer.WriteLine(");"); + Writer.Write("Writer.WriteString("); + Writer.Write(methodName); + Writer.Write("("); + if (!mapping.TypeDesc.UseReflection) Writer.Write("(" + fullTypeName + ")"); + Writer.WriteLine("o));"); + Writer.WriteLine("Writer.WriteEndElement();"); + Writer.WriteLine("return;"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else if (m is ArrayMapping && !m.IsSoap) + { + ArrayMapping mapping = m as ArrayMapping; + if (mapping == null || m.IsSoap) continue; + string fullTypeName = mapping.TypeDesc.CSharpName; + Writer.Write("else if ("); + if (mapping.TypeDesc.IsArray) + WriteArrayTypeCompare("t", fullTypeName, mapping.TypeDesc.ArrayElementTypeDesc.CSharpName, mapping.TypeDesc.UseReflection); + else + WriteTypeCompare("t", fullTypeName, mapping.TypeDesc.UseReflection); + Writer.WriteLine(") {"); + Writer.Indent++; + + Writer.WriteLine("Writer.WriteStartElement(n, ns);"); + Writer.Write("WriteXsiType("); + WriteQuotedCSharpString(mapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(mapping.Namespace); + Writer.WriteLine(");"); + + WriteMember("o", null, mapping.ElementsSortedByDerivation, null, null, mapping.TypeDesc, true); + + Writer.WriteLine("Writer.WriteEndElement();"); + Writer.WriteLine("return;"); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + } + } + + private void WriteStructMethod(StructMapping mapping) + { + if (mapping.IsSoap && mapping.TypeDesc.IsRoot) return; + string methodName = (string)MethodNames[mapping]; + + Writer.WriteLine(); + Writer.Write("void "); + Writer.Write(methodName); + + string fullTypeName = mapping.TypeDesc.CSharpName; + + if (mapping.IsSoap) + { + Writer.WriteLine("(object s) {"); + Writer.Indent++; + WriteLocalDecl(fullTypeName, "o", "s", mapping.TypeDesc.UseReflection); + } + else + { + Writer.Write("(string n, string ns, "); + Writer.Write(mapping.TypeDesc.UseReflection ? "object" : fullTypeName); + Writer.Write(" o"); + if (mapping.TypeDesc.IsNullable) + Writer.Write(", bool isNullable"); + Writer.WriteLine(", bool needType) {"); + Writer.Indent++; + if (mapping.TypeDesc.IsNullable) + { + Writer.WriteLine("if ((object)o == null) {"); + Writer.Indent++; + Writer.WriteLine("if (isNullable) WriteNullTagLiteral(n, ns);"); + Writer.WriteLine("return;"); + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.WriteLine("if (!needType) {"); + Writer.Indent++; + + Writer.Write(typeof(Type).FullName); + Writer.WriteLine(" t = o.GetType();"); + Writer.Write("if ("); + WriteTypeCompare("t", fullTypeName, mapping.TypeDesc.UseReflection); + Writer.WriteLine(") {"); + Writer.WriteLine("}"); + WriteDerivedTypes(mapping); + if (mapping.TypeDesc.IsRoot) + WriteEnumAndArrayTypes(); + Writer.WriteLine("else {"); + + Writer.Indent++; + if (mapping.TypeDesc.IsRoot) + { + Writer.WriteLine("WriteTypedPrimitive(n, ns, o, true);"); + Writer.WriteLine("return;"); + } + else + { + Writer.WriteLine("throw CreateUnknownTypeException(o);"); + } + Writer.Indent--; + Writer.WriteLine("}"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + if (!mapping.TypeDesc.IsAbstract) + { + if (mapping.TypeDesc.Type != null && typeof(XmlSchemaObject).IsAssignableFrom(mapping.TypeDesc.Type)) + { + Writer.WriteLine("EscapeName = false;"); + } + + string xmlnsSource = null; + MemberMapping[] members = TypeScope.GetAllMembers(mapping); + int xmlnsMember = FindXmlnsIndex(members); + if (xmlnsMember >= 0) + { + MemberMapping member = members[xmlnsMember]; + CodeIdentifier.CheckValidIdentifier(member.Name); + xmlnsSource = RaCodeGen.GetStringForMember("o", member.Name, mapping.TypeDesc); + if (mapping.TypeDesc.UseReflection) + { + xmlnsSource = "((" + member.TypeDesc.CSharpName + ")" + xmlnsSource + ")"; + } + } + + if (!mapping.IsSoap) + { + Writer.Write("WriteStartElement(n, ns, o, false, "); + if (xmlnsSource == null) + Writer.Write("null"); + else + Writer.Write(xmlnsSource); + + Writer.WriteLine(");"); + if (!mapping.TypeDesc.IsRoot) + { + Writer.Write("if (needType) WriteXsiType("); + WriteQuotedCSharpString(mapping.TypeName); + Writer.Write(", "); + WriteQuotedCSharpString(mapping.Namespace); + Writer.WriteLine(");"); + } + } + else if (xmlnsSource != null) + { + WriteNamespaces(xmlnsSource); + } + for (int i = 0; i < members.Length; i++) + { + MemberMapping m = members[i]; + if (m.Attribute != null) + { + CodeIdentifier.CheckValidIdentifier(m.Name); + if (m.CheckShouldPersist) + { + Writer.Write("if ("); + string methodInvoke = RaCodeGen.GetStringForMethodInvoke("o", fullTypeName, "ShouldSerialize" + m.Name, mapping.TypeDesc.UseReflection); + if (mapping.TypeDesc.UseReflection) methodInvoke = "((" + typeof(bool).FullName + ")" + methodInvoke + ")"; + Writer.Write(methodInvoke); + Writer.WriteLine(") {"); + Writer.Indent++; + } + if (m.CheckSpecified != SpecifiedAccessor.None) + { + Writer.Write("if ("); + string memberGet = RaCodeGen.GetStringForMember("o", m.Name + "Specified", mapping.TypeDesc); + if (mapping.TypeDesc.UseReflection) memberGet = "((" + typeof(bool).FullName + ")" + memberGet + ")"; + Writer.Write(memberGet); + Writer.WriteLine(") {"); + Writer.Indent++; + } + WriteMember(RaCodeGen.GetStringForMember("o", m.Name, mapping.TypeDesc), m.Attribute, m.TypeDesc, "o"); + + if (m.CheckSpecified != SpecifiedAccessor.None) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + if (m.CheckShouldPersist) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + } + } + + for (int i = 0; i < members.Length; i++) + { + MemberMapping m = members[i]; + if (m.Xmlns != null) + continue; + CodeIdentifier.CheckValidIdentifier(m.Name); + bool checkShouldPersist = m.CheckShouldPersist && (m.Elements.Length > 0 || m.Text != null); + + if (checkShouldPersist) + { + Writer.Write("if ("); + string methodInvoke = RaCodeGen.GetStringForMethodInvoke("o", fullTypeName, "ShouldSerialize" + m.Name, mapping.TypeDesc.UseReflection); + if (mapping.TypeDesc.UseReflection) methodInvoke = "((" + typeof(bool).FullName + ")" + methodInvoke + ")"; + Writer.Write(methodInvoke); + Writer.WriteLine(") {"); + Writer.Indent++; + } + if (m.CheckSpecified != SpecifiedAccessor.None) + { + Writer.Write("if ("); + string memberGet = RaCodeGen.GetStringForMember("o", m.Name + "Specified", mapping.TypeDesc); + if (mapping.TypeDesc.UseReflection) memberGet = "((" + typeof(bool).FullName + ")" + memberGet + ")"; + Writer.Write(memberGet); + Writer.WriteLine(") {"); + Writer.Indent++; + } + + string choiceSource = null; + if (m.ChoiceIdentifier != null) + { + CodeIdentifier.CheckValidIdentifier(m.ChoiceIdentifier.MemberName); + choiceSource = RaCodeGen.GetStringForMember("o", m.ChoiceIdentifier.MemberName, mapping.TypeDesc); + } + WriteMember(RaCodeGen.GetStringForMember("o", m.Name, mapping.TypeDesc), choiceSource, m.ElementsSortedByDerivation, m.Text, m.ChoiceIdentifier, m.TypeDesc, true); + + if (m.CheckSpecified != SpecifiedAccessor.None) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + if (checkShouldPersist) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + } + if (!mapping.IsSoap) + { + WriteEndElement("o"); + } + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private bool CanOptimizeWriteListSequence(TypeDesc listElementTypeDesc) + { + // check to see if we can write values of the attribute sequentially + // currently we have only one data type (XmlQualifiedName) that we can not write "inline", + // because we need to output xmlns:qx="..." for each of the qnames + + return (listElementTypeDesc != null && listElementTypeDesc != QnameTypeDesc); + } + + private void WriteMember(string source, AttributeAccessor attribute, TypeDesc memberTypeDesc, string parent) + { + if (memberTypeDesc.IsAbstract) return; + if (memberTypeDesc.IsArrayLike) + { + Writer.WriteLine("{"); + Writer.Indent++; + string fullTypeName = memberTypeDesc.CSharpName; + WriteArrayLocalDecl(fullTypeName, "a", source, memberTypeDesc); + if (memberTypeDesc.IsNullable) + { + Writer.WriteLine("if (a != null) {"); + Writer.Indent++; + } + if (attribute.IsList) + { + if (CanOptimizeWriteListSequence(memberTypeDesc.ArrayElementTypeDesc)) + { + Writer.Write("Writer.WriteStartAttribute(null, "); + WriteQuotedCSharpString(attribute.Name); + Writer.Write(", "); + string ns = attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : String.Empty; + if (ns != null) + { + WriteQuotedCSharpString(ns); + } + else + { + Writer.Write("null"); + } + Writer.WriteLine(");"); + } + else + { + Writer.Write(typeof(StringBuilder).FullName); + Writer.Write(" sb = new "); + Writer.Write(typeof(StringBuilder).FullName); + Writer.WriteLine("();"); + } + } + TypeDesc arrayElementTypeDesc = memberTypeDesc.ArrayElementTypeDesc; + + if (memberTypeDesc.IsEnumerable) + { + Writer.Write(" e = "); + Writer.Write(typeof(IEnumerator).FullName); + if (memberTypeDesc.IsPrivateImplementation) + { + Writer.Write("(("); + Writer.Write(typeof(IEnumerable).FullName); + Writer.WriteLine(").GetEnumerator();"); + } + else if (memberTypeDesc.IsGenericInterface) + { + if (memberTypeDesc.UseReflection) + { + // we use wildcard method name for generic GetEnumerator method, so we cannot use GetStringForMethodInvoke call here + Writer.Write("("); + Writer.Write(typeof(IEnumerator).FullName); + Writer.Write(")"); + Writer.Write(RaCodeGen.GetReflectionVariable(memberTypeDesc.CSharpName, "System.Collections.Generic.IEnumerable*")); + Writer.WriteLine(".Invoke(a, new object[0]);"); + } + else + { + Writer.Write("((System.Collections.Generic.IEnumerable<"); + Writer.Write(arrayElementTypeDesc.CSharpName); + Writer.WriteLine(">)a).GetEnumerator();"); + } + } + else + { + if (memberTypeDesc.UseReflection) + { + Writer.Write("("); + Writer.Write(typeof(IEnumerator).FullName); + Writer.Write(")"); + } + Writer.Write(RaCodeGen.GetStringForMethodInvoke("a", memberTypeDesc.CSharpName, "GetEnumerator", memberTypeDesc.UseReflection)); + Writer.WriteLine(";"); + } + Writer.WriteLine("if (e != null)"); + Writer.WriteLine("while (e.MoveNext()) {"); + Writer.Indent++; + + string arrayTypeFullName = arrayElementTypeDesc.CSharpName; + WriteLocalDecl(arrayTypeFullName, "ai", "e.Current", arrayElementTypeDesc.UseReflection); + } + else + { + Writer.Write("for (int i = 0; i < "); + if (memberTypeDesc.IsArray) + { + Writer.WriteLine("a.Length; i++) {"); + } + else + { + Writer.Write("(("); + Writer.Write(typeof(ICollection).FullName); + Writer.WriteLine(")a).Count; i++) {"); + } + Writer.Indent++; + string arrayTypeFullName = arrayElementTypeDesc.CSharpName; + WriteLocalDecl(arrayTypeFullName, "ai", RaCodeGen.GetStringForArrayMember("a", "i", memberTypeDesc), arrayElementTypeDesc.UseReflection); + } + if (attribute.IsList) + { + // check to see if we can write values of the attribute sequentially + if (CanOptimizeWriteListSequence(memberTypeDesc.ArrayElementTypeDesc)) + { + Writer.WriteLine("if (i != 0) Writer.WriteString(\" \");"); + Writer.Write("WriteValue("); + } + else + { + Writer.WriteLine("if (i != 0) sb.Append(\" \");"); + Writer.Write("sb.Append("); + } + if (attribute.Mapping is EnumMapping) + WriteEnumValue((EnumMapping)attribute.Mapping, "ai"); + else + WritePrimitiveValue(arrayElementTypeDesc, "ai", true); + Writer.WriteLine(");"); + } + else + { + WriteAttribute("ai", attribute, parent); + } + Writer.Indent--; + Writer.WriteLine("}"); + if (attribute.IsList) + { + // check to see if we can write values of the attribute sequentially + if (CanOptimizeWriteListSequence(memberTypeDesc.ArrayElementTypeDesc)) + { + Writer.WriteLine("Writer.WriteEndAttribute();"); + } + else + { + Writer.WriteLine("if (sb.Length != 0) {"); + Writer.Indent++; + + Writer.Write("WriteAttribute("); + WriteQuotedCSharpString(attribute.Name); + Writer.Write(", "); + string ns = attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : String.Empty; + if (ns != null) + { + WriteQuotedCSharpString(ns); + Writer.Write(", "); + } + Writer.WriteLine("sb.ToString());"); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + if (memberTypeDesc.IsNullable) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + WriteAttribute(source, attribute, parent); + } + } + + private void WriteAttribute(string source, AttributeAccessor attribute, string parent) + { + if (attribute.Mapping is SpecialMapping) + { + SpecialMapping special = (SpecialMapping)attribute.Mapping; + if (special.TypeDesc.Kind == TypeKind.Attribute || special.TypeDesc.CanBeAttributeValue) + { + Writer.Write("WriteXmlAttribute("); + Writer.Write(source); + Writer.Write(", "); + Writer.Write(parent); + Writer.WriteLine(");"); + } + else + throw new InvalidOperationException(SR.XmlInternalError); + } + else + { + TypeDesc typeDesc = attribute.Mapping.TypeDesc; + if (!typeDesc.UseReflection) source = "((" + typeDesc.CSharpName + ")" + source + ")"; + WritePrimitive("WriteAttribute", attribute.Name, attribute.Form == XmlSchemaForm.Qualified ? attribute.Namespace : "", attribute.Default, source, attribute.Mapping, false, false, false); + } + } + + private void WriteMember(string source, string choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc memberTypeDesc, bool writeAccessors) + { + if (memberTypeDesc.IsArrayLike && + !(elements.Length == 1 && elements[0].Mapping is ArrayMapping)) + WriteArray(source, choiceSource, elements, text, choice, memberTypeDesc); + else + WriteElements(source, choiceSource, elements, text, choice, "a", writeAccessors, memberTypeDesc.IsNullable); + } + + + private void WriteArray(string source, string choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc arrayTypeDesc) + { + if (elements.Length == 0 && text == null) return; + Writer.WriteLine("{"); + Writer.Indent++; + string arrayTypeName = arrayTypeDesc.CSharpName; + WriteArrayLocalDecl(arrayTypeName, "a", source, arrayTypeDesc); + if (arrayTypeDesc.IsNullable) + { + Writer.WriteLine("if (a != null) {"); + Writer.Indent++; + } + + if (choice != null) + { + bool choiceUseReflection = choice.Mapping.TypeDesc.UseReflection; + string choiceFullName = choice.Mapping.TypeDesc.CSharpName; + WriteArrayLocalDecl(choiceFullName + "[]", "c", choiceSource, choice.Mapping.TypeDesc); + // write check for the choice identifier array + Writer.WriteLine("if (c == null || c.Length < a.Length) {"); + Writer.Indent++; + Writer.Write("throw CreateInvalidChoiceIdentifierValueException("); + WriteQuotedCSharpString(choice.Mapping.TypeDesc.FullName); + Writer.Write(", "); + WriteQuotedCSharpString(choice.MemberName); + Writer.Write(");"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + WriteArrayItems(elements, text, choice, arrayTypeDesc, "a", "c"); + if (arrayTypeDesc.IsNullable) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteArrayItems(ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc arrayTypeDesc, string arrayName, string choiceName) + { + TypeDesc arrayElementTypeDesc = arrayTypeDesc.ArrayElementTypeDesc; + + if (arrayTypeDesc.IsEnumerable) + { + Writer.Write(typeof(IEnumerator).FullName); + Writer.Write(" e = "); + if (arrayTypeDesc.IsPrivateImplementation) + { + Writer.Write("(("); + Writer.Write(typeof(IEnumerable).FullName); + Writer.Write(")"); + Writer.Write(arrayName); + Writer.WriteLine(").GetEnumerator();"); + } + else if (arrayTypeDesc.IsGenericInterface) + { + if (arrayTypeDesc.UseReflection) + { + // we use wildcard method name for generic GetEnumerator method, so we cannot use GetStringForMethodInvoke call here + Writer.Write("("); + Writer.Write(typeof(IEnumerator).FullName); + Writer.Write(")"); + Writer.Write(RaCodeGen.GetReflectionVariable(arrayTypeDesc.CSharpName, "System.Collections.Generic.IEnumerable*")); + Writer.Write(".Invoke("); + Writer.Write(arrayName); + Writer.WriteLine(", new object[0]);"); + } + else + { + Writer.Write("((System.Collections.Generic.IEnumerable<"); + Writer.Write(arrayElementTypeDesc.CSharpName); + Writer.Write(">)"); + Writer.Write(arrayName); + Writer.WriteLine(").GetEnumerator();"); + } + } + else + { + if (arrayTypeDesc.UseReflection) + { + Writer.Write("("); + Writer.Write(typeof(IEnumerator).FullName); + Writer.Write(")"); + } + Writer.Write(RaCodeGen.GetStringForMethodInvoke(arrayName, arrayTypeDesc.CSharpName, "GetEnumerator", arrayTypeDesc.UseReflection)); + Writer.WriteLine(";"); + } + Writer.WriteLine("if (e != null)"); + Writer.WriteLine("while (e.MoveNext()) {"); + Writer.Indent++; + string arrayTypeFullName = arrayElementTypeDesc.CSharpName; + WriteLocalDecl(arrayTypeFullName, arrayName + "i", "e.Current", arrayElementTypeDesc.UseReflection); + WriteElements(arrayName + "i", choiceName + "i", elements, text, choice, arrayName + "a", true, true); + } + else + { + Writer.Write("for (int i"); + Writer.Write(arrayName); + Writer.Write(" = 0; i"); + Writer.Write(arrayName); + Writer.Write(" < "); + if (arrayTypeDesc.IsArray) + { + Writer.Write(arrayName); + Writer.Write(".Length"); + } + else + { + Writer.Write("(("); + Writer.Write(typeof(ICollection).FullName); + Writer.Write(")"); + Writer.Write(arrayName); + Writer.Write(").Count"); + } + Writer.Write("; i"); + Writer.Write(arrayName); + Writer.WriteLine("++) {"); + Writer.Indent++; + int count = elements.Length + (text == null ? 0 : 1); + if (count > 1) + { + string arrayTypeFullName = arrayElementTypeDesc.CSharpName; + WriteLocalDecl(arrayTypeFullName, arrayName + "i", RaCodeGen.GetStringForArrayMember(arrayName, "i" + arrayName, arrayTypeDesc), arrayElementTypeDesc.UseReflection); + if (choice != null) + { + string choiceFullName = choice.Mapping.TypeDesc.CSharpName; + WriteLocalDecl(choiceFullName, choiceName + "i", RaCodeGen.GetStringForArrayMember(choiceName, "i" + arrayName, choice.Mapping.TypeDesc), choice.Mapping.TypeDesc.UseReflection); + } + WriteElements(arrayName + "i", choiceName + "i", elements, text, choice, arrayName + "a", true, arrayElementTypeDesc.IsNullable); + } + else + { + WriteElements(RaCodeGen.GetStringForArrayMember(arrayName, "i" + arrayName, arrayTypeDesc), elements, text, choice, arrayName + "a", true, arrayElementTypeDesc.IsNullable); + } + } + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteElements(string source, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, string arrayName, bool writeAccessors, bool isNullable) + { + WriteElements(source, null, elements, text, choice, arrayName, writeAccessors, isNullable); + } + + private void WriteElements(string 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.UseReflection && !elements[0].Mapping.TypeDesc.IsOptionalValue) + source = "((" + td.CSharpName + ")" + source + ")"; + WriteElement(source, elements[0], arrayName, writeAccessors); + } + else + { + if (isNullable && choice == null) + { + Writer.Write("if ((object)("); + Writer.Write(source); + Writer.Write(") != null)"); + } + Writer.WriteLine("{"); + Writer.Indent++; + 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) + { + bool useReflection = element.Mapping.TypeDesc.UseReflection; + string fullTypeName = element.Mapping.TypeDesc.CSharpName; + bool enumUseReflection = choice.Mapping.TypeDesc.UseReflection; + string enumFullName = (enumUseReflection ? "" : enumTypeName + ".@") + FindChoiceEnumValue(element, (EnumMapping)choice.Mapping, enumUseReflection); + + if (wroteFirstIf) Writer.Write("else "); + else wroteFirstIf = true; + Writer.Write("if ("); + Writer.Write(enumUseReflection ? RaCodeGen.GetStringForEnumLongValue(enumSource, enumUseReflection) : enumSource); + Writer.Write(" == "); + Writer.Write(enumFullName); + if (isNullable && !element.IsNullable) + { + Writer.Write(" && ((object)("); + Writer.Write(source); + Writer.Write(") != null)"); + } + Writer.WriteLine(") {"); + Writer.Indent++; + + WriteChoiceTypeCheck(source, fullTypeName, useReflection, choice, enumFullName, element.Mapping.TypeDesc); + + string castedSource = source; + if (!useReflection) + castedSource = "((" + fullTypeName + ")" + source + ")"; + WriteElement(element.Any ? source : castedSource, element, arrayName, writeAccessors); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + bool useReflection = element.Mapping.TypeDesc.UseReflection; + TypeDesc td = element.IsUnbounded ? element.Mapping.TypeDesc.CreateArrayTypeDesc() : element.Mapping.TypeDesc; + string fullTypeName = td.CSharpName; + if (wroteFirstIf) Writer.Write("else "); + else wroteFirstIf = true; + Writer.Write("if ("); + WriteInstanceOf(source, fullTypeName, useReflection); + Writer.WriteLine(") {"); + Writer.Indent++; + string castedSource = source; + if (!useReflection) + castedSource = "((" + fullTypeName + ")" + source + ")"; + WriteElement(element.Any ? source : castedSource, element, arrayName, writeAccessors); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + if (anyCount > 0) + { + if (elements.Length - anyCount > 0) Writer.Write("else "); + + string fullTypeName = typeof(XmlElement).FullName; + + Writer.Write("if ("); + Writer.Write(source); + Writer.Write(" is "); + Writer.Write(fullTypeName); + Writer.WriteLine(") {"); + Writer.Indent++; + + Writer.Write(fullTypeName); + Writer.Write(" elem = ("); + Writer.Write(fullTypeName); + Writer.Write(")"); + Writer.Write(source); + Writer.WriteLine(";"); + + int c = 0; + + foreach (ElementAccessor element in namedAnys) + { + if (c++ > 0) Writer.Write("else "); + + string enumFullName = null; + + bool useReflection = element.Mapping.TypeDesc.UseReflection; + if (choice != null) + { + bool enumUseReflection = choice.Mapping.TypeDesc.UseReflection; + enumFullName = (enumUseReflection ? "" : enumTypeName + ".@") + FindChoiceEnumValue(element, (EnumMapping)choice.Mapping, enumUseReflection); + Writer.Write("if ("); + Writer.Write(enumUseReflection ? RaCodeGen.GetStringForEnumLongValue(enumSource, enumUseReflection) : enumSource); + Writer.Write(" == "); + Writer.Write(enumFullName); + if (isNullable && !element.IsNullable) + { + Writer.Write(" && ((object)("); + Writer.Write(source); + Writer.Write(") != null)"); + } + Writer.WriteLine(") {"); + Writer.Indent++; + } + Writer.Write("if (elem.Name == "); + WriteQuotedCSharpString(element.Name); + Writer.Write(" && elem.NamespaceURI == "); + WriteQuotedCSharpString(element.Namespace); + Writer.WriteLine(") {"); + Writer.Indent++; + WriteElement("elem", element, arrayName, writeAccessors); + + if (choice != null) + { + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else {"); + Writer.Indent++; + + Writer.WriteLine("// throw Value '{0}' of the choice identifier '{1}' does not match element '{2}' from namespace '{3}'."); + + Writer.Write("throw CreateChoiceIdentifierValueException("); + WriteQuotedCSharpString(enumFullName); + Writer.Write(", "); + WriteQuotedCSharpString(choice.MemberName); + Writer.WriteLine(", elem.Name, elem.NamespaceURI);"); + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + if (c > 0) + { + Writer.WriteLine("else {"); + Writer.Indent++; + } + if (unnamedAny != null) + { + WriteElement("elem", unnamedAny, arrayName, writeAccessors); + } + else + { + Writer.WriteLine("throw CreateUnknownAnyElementException(elem.Name, elem.NamespaceURI);"); + } + if (c > 0) + { + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + if (text != null) + { + bool useReflection = text.Mapping.TypeDesc.UseReflection; + string fullTypeName = text.Mapping.TypeDesc.CSharpName; + if (elements.Length > 0) + { + Writer.Write("else "); + Writer.Write("if ("); + WriteInstanceOf(source, fullTypeName, useReflection); + Writer.WriteLine(") {"); + Writer.Indent++; + string castedSource = source; + if (!useReflection) + castedSource = "((" + fullTypeName + ")" + source + ")"; + WriteText(castedSource, text); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + string castedSource = source; + if (!useReflection) + castedSource = "((" + fullTypeName + ")" + source + ")"; + WriteText(castedSource, text); + } + } + if (elements.Length > 0) + { + Writer.Write("else "); + + if (isNullable) + { + Writer.Write(" if ((object)("); + Writer.Write(source); + Writer.Write(") != null)"); + } + + Writer.WriteLine("{"); + Writer.Indent++; + + Writer.Write("throw CreateUnknownTypeException("); + Writer.Write(source); + Writer.WriteLine(");"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + Writer.Indent--; + Writer.WriteLine("}"); + } + } + + private void WriteText(string source, TextAccessor text) + { + if (text.Mapping is PrimitiveMapping) + { + PrimitiveMapping mapping = (PrimitiveMapping)text.Mapping; + Writer.Write("WriteValue("); + if (text.Mapping is EnumMapping) + { + WriteEnumValue((EnumMapping)text.Mapping, source); + } + else + { + WritePrimitiveValue(mapping.TypeDesc, source, false); + } + Writer.WriteLine(");"); + } + else if (text.Mapping is SpecialMapping) + { + SpecialMapping mapping = (SpecialMapping)text.Mapping; + switch (mapping.TypeDesc.Kind) + { + case TypeKind.Node: + Writer.Write(source); + Writer.WriteLine(".WriteTo(Writer);"); + break; + default: + throw new InvalidOperationException(SR.XmlInternalError); + } + } + } + + private void WriteElement(string 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) + { + Writer.Write("if ("); + Writer.Write(source); + Writer.WriteLine(" != null) {"); + Writer.Indent++; + string fullTypeName = element.Mapping.TypeDesc.BaseTypeDesc.CSharpName; + string castedSource = source; + if (!element.Mapping.TypeDesc.BaseTypeDesc.UseReflection) + castedSource = "((" + fullTypeName + ")" + source + ")"; + ElementAccessor e = element.Clone(); + e.Mapping = ((NullableMapping)element.Mapping).BaseMapping; + WriteElement(e.Any ? source : castedSource, e, arrayName, writeAccessor); + Writer.Indent--; + Writer.WriteLine("}"); + if (element.IsNullable) + { + Writer.WriteLine("else {"); + Writer.Indent++; + WriteLiteralNullTag(element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + else if (element.Mapping is ArrayMapping) + { + ArrayMapping mapping = (ArrayMapping)element.Mapping; + if (mapping.IsSoap) + { + Writer.Write("WritePotentiallyReferencingElement("); + WriteQuotedCSharpString(name); + Writer.Write(", "); + WriteQuotedCSharpString(ns); + Writer.Write(", "); + Writer.Write(source); + if (!writeAccessor) + { + Writer.Write(", "); + Writer.Write(RaCodeGen.GetStringForTypeof(mapping.TypeDesc.CSharpName, mapping.TypeDesc.UseReflection)); + Writer.Write(", true, "); + } + else + { + Writer.Write(", null, false, "); + } + WriteValue(element.IsNullable); + Writer.WriteLine(");"); + } + else if (element.IsUnbounded) + { + TypeDesc td = mapping.TypeDesc.CreateArrayTypeDesc(); + string fullTypeName = td.CSharpName; + string elementArrayName = "el" + arrayName; + string arrayIndex = "c" + elementArrayName; + Writer.WriteLine("{"); + Writer.Indent++; + WriteArrayLocalDecl(fullTypeName, elementArrayName, source, mapping.TypeDesc); + if (element.IsNullable) + { + WriteNullCheckBegin(elementArrayName, element); + } + else + { + if (mapping.TypeDesc.IsNullable) + { + Writer.Write("if ("); + Writer.Write(elementArrayName); + Writer.Write(" != null)"); + } + Writer.WriteLine("{"); + Writer.Indent++; + } + + Writer.Write("for (int "); + Writer.Write(arrayIndex); + Writer.Write(" = 0; "); + Writer.Write(arrayIndex); + Writer.Write(" < "); + + if (td.IsArray) + { + Writer.Write(elementArrayName); + Writer.Write(".Length"); + } + else + { + Writer.Write("(("); + Writer.Write(typeof(ICollection).FullName); + Writer.Write(")"); + Writer.Write(elementArrayName); + Writer.Write(").Count"); + } + Writer.Write("; "); + Writer.Write(arrayIndex); + Writer.WriteLine("++) {"); + Writer.Indent++; + + element.IsUnbounded = false; + WriteElement(elementArrayName + "[" + arrayIndex + "]", element, arrayName, writeAccessor); + element.IsUnbounded = true; + + Writer.Indent--; + Writer.WriteLine("}"); + + Writer.Indent--; + Writer.WriteLine("}"); + Writer.Indent--; + Writer.WriteLine("}"); + } + else + { + string fullTypeName = mapping.TypeDesc.CSharpName; + Writer.WriteLine("{"); + Writer.Indent++; + WriteArrayLocalDecl(fullTypeName, arrayName, source, mapping.TypeDesc); + if (element.IsNullable) + { + WriteNullCheckBegin(arrayName, element); + } + else + { + if (mapping.TypeDesc.IsNullable) + { + Writer.Write("if ("); + Writer.Write(arrayName); + Writer.Write(" != null)"); + } + Writer.WriteLine("{"); + Writer.Indent++; + } + WriteStartElement(name, ns, false); + WriteArrayItems(mapping.ElementsSortedByDerivation, null, null, mapping.TypeDesc, arrayName, null); + WriteEndElement(); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.Indent--; + Writer.WriteLine("}"); + } + } + else if (element.Mapping is EnumMapping) + { + if (element.Mapping.IsSoap) + { + string methodName = (string)MethodNames[element.Mapping]; + Writer.Write("Writer.WriteStartElement("); + WriteQuotedCSharpString(name); + Writer.Write(", "); + WriteQuotedCSharpString(ns); + Writer.WriteLine(");"); + Writer.Write(methodName); + Writer.Write("("); + Writer.Write(source); + Writer.WriteLine(");"); + WriteEndElement(); + } + else + { + 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.IsSoap, mapping); + else + { + string suffixNullable = mapping.IsSoap ? "Encoded" : "Literal"; + string suffixRaw = mapping.TypeDesc.XmlEncodingNotRequired ? "Raw" : ""; + WritePrimitive(element.IsNullable ? ("WriteNullableString" + suffixNullable + suffixRaw) : ("WriteElementString" + suffixRaw), + name, ns, element.Default, source, mapping, mapping.IsSoap, true, element.IsNullable); + } + } + else if (element.Mapping is StructMapping) + { + StructMapping mapping = (StructMapping)element.Mapping; + + if (mapping.IsSoap) + { + Writer.Write("WritePotentiallyReferencingElement("); + WriteQuotedCSharpString(name); + Writer.Write(", "); + WriteQuotedCSharpString(ns); + Writer.Write(", "); + Writer.Write(source); + if (!writeAccessor) + { + Writer.Write(", "); + Writer.Write(RaCodeGen.GetStringForTypeof(mapping.TypeDesc.CSharpName, mapping.TypeDesc.UseReflection)); + Writer.Write(", true, "); + } + else + { + Writer.Write(", null, false, "); + } + WriteValue(element.IsNullable); + } + else + { + 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) + Environment.StackTrace); +#endif + Writer.Write(methodName); + Writer.Write("("); + WriteQuotedCSharpString(name); + Writer.Write(", "); + if (ns == null) + Writer.Write("null"); + else + { + WriteQuotedCSharpString(ns); + } + Writer.Write(", "); + Writer.Write(source); + if (mapping.TypeDesc.IsNullable) + { + Writer.Write(", "); + WriteValue(element.IsNullable); + } + Writer.Write(", false"); + } + Writer.WriteLine(");"); + } + else if (element.Mapping is SpecialMapping) + { + SpecialMapping mapping = (SpecialMapping)element.Mapping; + bool useReflection = mapping.TypeDesc.UseReflection; + 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 + Writer.Write("if (("); + Writer.Write(source); + Writer.Write(") is "); + Writer.Write(typeof(XmlNode).FullName); + Writer.Write(" || "); + Writer.Write(source); + Writer.Write(" == null"); + Writer.WriteLine(") {"); + Writer.Indent++; + + WriteElementCall("WriteElementLiteral", typeof(XmlNode), source, name, ns, element.IsNullable, element.Any); + + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else {"); + Writer.Indent++; + + Writer.Write("throw CreateInvalidAnyTypeException("); + Writer.Write(source); + Writer.WriteLine(");"); + + Writer.Indent--; + Writer.WriteLine("}"); + } + } + else + { + throw new InvalidOperationException(SR.XmlInternalError); + } + } + + private void WriteElementCall(string func, Type cast, string source, string name, string ns, bool isNullable, bool isAny) + { + Writer.Write(func); + Writer.Write("(("); + Writer.Write(cast.FullName); + Writer.Write(")"); + Writer.Write(source); + Writer.Write(", "); + WriteQuotedCSharpString(name); + Writer.Write(", "); + WriteQuotedCSharpString(ns); + Writer.Write(", "); + WriteValue(isNullable); + Writer.Write(", "); + WriteValue(isAny); + Writer.WriteLine(");"); + } + + private void WriteCheckDefault(TypeMapping mapping, string source, object value, bool isNullable) + { + Writer.Write("if ("); + + if (value is string && ((string)value).Length == 0) + { + // special case for string compare + Writer.Write("("); + Writer.Write(source); + if (isNullable) + Writer.Write(" == null) || ("); + else + Writer.Write(" != null) && ("); + Writer.Write(source); + Writer.Write(".Length != 0)"); + } + else + { + Writer.Write(source); + Writer.Write(" != "); + Type type = Type.GetType(mapping.TypeDesc.Type.FullName); + WriteValue(type != null ? Convert.ChangeType(value, type) : value); + } + Writer.Write(")"); + } + + private void WriteChoiceTypeCheck(string source, string fullTypeName, bool useReflection, ChoiceIdentifierAccessor choice, string enumName, TypeDesc typeDesc) + { + Writer.Write("if (((object)"); + Writer.Write(source); + Writer.Write(") != null && !("); + WriteInstanceOf(source, fullTypeName, useReflection); + Writer.Write(")) throw CreateMismatchChoiceException("); + WriteQuotedCSharpString(typeDesc.FullName); + Writer.Write(", "); + WriteQuotedCSharpString(choice.MemberName); + Writer.Write(", "); + WriteQuotedCSharpString(enumName); + Writer.WriteLine(");"); + } + + private void WriteNullCheckBegin(string source, ElementAccessor element) + { + Writer.Write("if ((object)("); + Writer.Write(source); + Writer.WriteLine(") == null) {"); + Writer.Indent++; + WriteLiteralNullTag(element.Name, element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.WriteLine("else {"); + Writer.Indent++; + } + + private void WriteValue(object value) + { + if (value == null) + { + Writer.Write("null"); + } + else + { + Type type = value.GetType(); + + if (type == typeof(String)) + { + string s = (string)value; + WriteQuotedCSharpString(s); + } + else if (type == typeof(Char)) + { + Writer.Write('\''); + char ch = (char)value; + if (ch == '\'') + Writer.Write("\'"); + else + Writer.Write(ch); + Writer.Write('\''); + } + else if (type == typeof(Int32)) + Writer.Write(((Int32)value).ToString(null, NumberFormatInfo.InvariantInfo)); + else if (type == typeof(Double)) + { + if (double.IsNaN((Double)value)) + { + Writer.Write("double.NaN"); + } + else + { + Writer.Write(((Double)value).ToString("R", NumberFormatInfo.InvariantInfo)); + } + } + else if (type == typeof(Boolean)) + Writer.Write((bool)value ? "true" : "false"); + else if ((type == typeof(Int16)) || (type == typeof(Int64)) || (type == typeof(UInt16)) || (type == typeof(UInt32)) || (type == typeof(UInt64)) || (type == typeof(Byte)) || (type == typeof(SByte))) + { + Writer.Write("("); + Writer.Write(type.FullName); + Writer.Write(")"); + Writer.Write("("); + Writer.Write(Convert.ToString(value, NumberFormatInfo.InvariantInfo)); + Writer.Write(")"); + } + else if (type == typeof(Single)) + { + if (Single.IsNaN((Single)value)) + { + Writer.Write("System.Single.NaN"); + } + else + { + Writer.Write(((Single)value).ToString("R", NumberFormatInfo.InvariantInfo)); + Writer.Write("f"); + } + } + else if (type == typeof(Decimal)) + { + Writer.Write(((Decimal)value).ToString(null, NumberFormatInfo.InvariantInfo)); + Writer.Write("m"); + } + else if (type == typeof(DateTime)) + { + Writer.Write(" new "); + Writer.Write(type.FullName); + Writer.Write("("); + Writer.Write(((DateTime)value).Ticks.ToString(CultureInfo.InvariantCulture)); + Writer.Write(")"); + } + else if (type == typeof(TimeSpan)) + { + Writer.Write(" new "); + Writer.Write(type.FullName); + Writer.Write("("); + Writer.Write(((TimeSpan)value).Ticks.ToString(CultureInfo.InvariantCulture)); + Writer.Write(")"); + } + else + { + if (type.IsEnum) + { + Writer.Write(((int)value).ToString(null, NumberFormatInfo.InvariantInfo)); + } + + else + { + throw new InvalidOperationException(SR.Format(SR.XmlUnsupportedDefaultType, type.FullName)); + } + } + } + } + + private void WriteNamespaces(string source) + { + Writer.Write("WriteNamespaceDeclarations("); + Writer.Write(source); + Writer.WriteLine(");"); + } + + private int FindXmlnsIndex(MemberMapping[] members) + { + for (int i = 0; i < members.Length; i++) + { + if (members[i].Xmlns == null) + continue; + return i; + } + return -1; + } + + private void WriteExtraMembers(string loopStartSource, string loopEndSource) + { + Writer.Write("for (int i = "); + Writer.Write(loopStartSource); + Writer.Write("; i < "); + Writer.Write(loopEndSource); + Writer.WriteLine("; i++) {"); + Writer.Indent++; + Writer.WriteLine("if (p[i] != null) {"); + Writer.Indent++; + Writer.WriteLine("WritePotentiallyReferencingElement(null, null, p[i], p[i].GetType(), true, false);"); + Writer.Indent--; + Writer.WriteLine("}"); + Writer.Indent--; + Writer.WriteLine("}"); + } + + private void WriteLocalDecl(string typeName, string variableName, string initValue, bool useReflection) + { + RaCodeGen.WriteLocalDecl(typeName, variableName, initValue, useReflection); + } + + private void WriteArrayLocalDecl(string typeName, string variableName, string initValue, TypeDesc arrayTypeDesc) + { + RaCodeGen.WriteArrayLocalDecl(typeName, variableName, initValue, arrayTypeDesc); + } + private void WriteTypeCompare(string variable, string escapedTypeName, bool useReflection) + { + RaCodeGen.WriteTypeCompare(variable, escapedTypeName, useReflection); + } + private void WriteInstanceOf(string source, string escapedTypeName, bool useReflection) + { + RaCodeGen.WriteInstanceOf(source, escapedTypeName, useReflection); + } + private void WriteArrayTypeCompare(string variable, string escapedTypeName, string elementTypeName, bool useReflection) + { + RaCodeGen.WriteArrayTypeCompare(variable, escapedTypeName, elementTypeName, useReflection); + } + + private void WriteEnumCase(string fullTypeName, ConstantMapping c, bool useReflection) + { + RaCodeGen.WriteEnumCase(fullTypeName, c, useReflection); + } + + private string FindChoiceEnumValue(ElementAccessor element, EnumMapping choiceMapping, bool useReflection) + { + string enumValue = null; + + for (int i = 0; i < choiceMapping.Constants.Length; i++) + { + string xmlName = choiceMapping.Constants[i].XmlName; + + if (element.Any && element.Name.Length == 0) + { + if (xmlName == "##any:") + { + if (useReflection) + enumValue = choiceMapping.Constants[i].Value.ToString(CultureInfo.InvariantCulture); + else + enumValue = choiceMapping.Constants[i].Name; + break; + } + continue; + } + int colon = xmlName.LastIndexOf(':'); + string choiceNs = colon < 0 ? choiceMapping.Namespace : xmlName.Substring(0, colon); + string choiceName = colon < 0 ? xmlName : xmlName.Substring(colon + 1); + + if (element.Name == choiceName) + { + if ((element.Form == XmlSchemaForm.Unqualified && string.IsNullOrEmpty(choiceNs)) || element.Namespace == choiceNs) + { + if (useReflection) + enumValue = choiceMapping.Constants[i].Value.ToString(CultureInfo.InvariantCulture); + else + enumValue = choiceMapping.Constants[i].Name; + break; + } + } + } + if (enumValue == null || enumValue.Length == 0) + { + if (element.Any && element.Name.Length == 0) + { + // Type {0} is missing enumeration value '##any' for XmlAnyElementAttribute. + throw new InvalidOperationException(SR.Format(SR.XmlChoiceMissingAnyValue, choiceMapping.TypeDesc.FullName)); + } + // Type {0} is missing value for '{1}'. + throw new InvalidOperationException(SR.Format(SR.XmlChoiceMissingValue, choiceMapping.TypeDesc.FullName, element.Namespace + ":" + element.Name, element.Name, element.Namespace)); + } + if (!useReflection) + CodeIdentifier.CheckValidIdentifier(enumValue); + return enumValue; + } + } #endif } diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs index 18532d5659..e7a3342436 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System.Collections; @@ -28,19 +24,13 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal struct XmlDeserializationEvents -#else public struct XmlDeserializationEvents -#endif { private XmlNodeEventHandler _onUnknownNode; private XmlAttributeEventHandler _onUnknownAttribute; private XmlElementEventHandler _onUnknownElement; private UnreferencedObjectEventHandler _onUnreferencedObject; -#if !XMLSERIALIZERGENERATOR internal object sender; -#endif /// <include file='doc\XmlSerializer.uex' path='docs/doc[@for="XmlDeserializationEvents.OnUnknownNode"]/*' /> public XmlNodeEventHandler OnUnknownNode @@ -101,11 +91,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal abstract class XmlSerializerImplementation -#else public abstract class XmlSerializerImplementation -#endif { /// <include file='doc\XmlSerializer.uex' path='docs/doc[@for="XmlSerializerImplementation.Reader"]/*' /> public virtual XmlSerializationReader Reader { get { throw new NotSupportedException(); } } @@ -143,11 +129,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlSerializer -#else public class XmlSerializer -#endif { #if FEATURE_SERIALIZATION_UAPAOT public static SerializationMode Mode { get; set; } = SerializationMode.ReflectionAsBackup; @@ -387,7 +369,6 @@ namespace System.Xml.Serialization return new TempAssembly(new XmlMapping[] { xmlMapping }, new Type[] { type }, defaultNamespace, location); } -#if !XMLSERIALIZERGENERATOR /// <include file='doc\XmlSerializer.uex' path='docs/doc[@for="XmlSerializer.Serialize"]/*' /> /// <devdoc> /// <para>[To be supplied.]</para> @@ -684,7 +665,6 @@ namespace System.Xml.Serialization var reader = new ReflectionXmlSerializationReader(mapping, xmlReader, events, encodingStyle); return reader.ReadObject(); } -#endif private static bool ShouldUseReflectionBasedSerialization(XmlMapping mapping) { @@ -764,6 +744,13 @@ namespace System.Xml.Serialization TempAssembly tempAssembly = null; if (assembly == null) { + if (Mode == SerializationMode.PreGenOnly) + { + AssemblyName name = type.Assembly.GetName(); + string serializerName = Compiler.GetTempAssemblyName(name, null); + throw new FileLoadException(SR.Format(SR.FailLoadAssemblyUnderPregenMode, serializerName)); + } + if (XmlMapping.IsShallow(mappings)) { return Array.Empty<XmlSerializer>(); @@ -815,7 +802,7 @@ namespace System.Xml.Serialization return serializers; } -#if XMLSERIALIZERGENERATOR +#if !FEATURE_SERIALIZATION_UAPAOT [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] public static bool GenerateSerializer(Type[] types, XmlMapping[] mappings, Stream stream) @@ -1074,7 +1061,6 @@ namespace System.Xml.Serialization return mapping; } -#if !XMLSERIALIZERGENERATOR private void SerializePrimitive(XmlWriter xmlWriter, object o, XmlSerializerNamespaces namespaces) { XmlSerializationPrimitiveWriter writer = new XmlSerializationPrimitiveWriter(); @@ -1231,7 +1217,6 @@ namespace System.Xml.Serialization return o; } -#endif private class XmlSerializerMappingKey { public XmlMapping Mapping; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs index 737106267f..cfd9374aff 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System.Collections; @@ -25,11 +21,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlSerializerFactory -#else public class XmlSerializerFactory -#endif { private static TempAssemblyCache s_cache = new TempAssemblyCache(); diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerNamespaces.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerNamespaces.cs index f4444900fa..7d772e0e67 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerNamespaces.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerNamespaces.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.Reflection; using System.Collections; @@ -20,11 +16,7 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlSerializerNamespaces -#else public class XmlSerializerNamespaces -#endif { private Dictionary<string, string> _namespaces = null; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlTypeMapping.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlTypeMapping.cs index 59debad11c..ead21258e2 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlTypeMapping.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlTypeMapping.cs @@ -6,20 +6,12 @@ using System.Reflection; using System; -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlTypeMapping : XmlMapping -#else public class XmlTypeMapping : XmlMapping -#endif { internal XmlTypeMapping(TypeScope scope, ElementAccessor accessor) : base(scope, accessor) { diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Xmlcustomformatter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Xmlcustomformatter.cs index 15a19486e8..5fb8b43de1 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/Xmlcustomformatter.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/Xmlcustomformatter.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System; using System.Xml; @@ -164,11 +160,8 @@ namespace System.Xml.Serialization return null; if (value.Length == 0) return ""; -#if XMLSERIALIZERGENERATOR - return System.Xml.Extensions.ExtensionMethods.ToBinHexString(value); -#else + return XmlConvert.ToBinHexString(value); -#endif } internal static string FromEnum(long val, string[] vals, long[] ids, string typeName) @@ -436,11 +429,7 @@ namespace System.Xml.Serialization { if (value == null) return null; value = value.Trim(); -#if XMLSERIALIZERGENERATOR - return System.Xml.Extensions.ExtensionMethods.FromBinHexString(value, true); -#else return XmlConvert.FromBinHexString(value); -#endif } internal static long ToEnum(string val, Hashtable vals, string typeName, bool validate) diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/_Events.cs b/src/System.Private.Xml/src/System/Xml/Serialization/_Events.cs index 0b681f3547..e4d013ba2d 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/_Events.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/_Events.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator -#else namespace System.Xml.Serialization -#endif { using System.IO; using System; @@ -19,21 +15,13 @@ namespace System.Xml.Serialization /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal delegate void XmlAttributeEventHandler(object sender, XmlAttributeEventArgs e); -#else public delegate void XmlAttributeEventHandler(object sender, XmlAttributeEventArgs e); -#endif /// <include file='doc\_Events.uex' path='docs/doc[@for="XmlAttributeEventArgs"]/*' /> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlAttributeEventArgs : EventArgs -#else public class XmlAttributeEventArgs : EventArgs -#endif { private object _o; private XmlAttribute _attr; @@ -105,18 +93,10 @@ namespace System.Xml.Serialization } /// <include file='doc\_Events.uex' path='docs/doc[@for="XmlElementEventHandler"]/*' /> -#if XMLSERIALIZERGENERATOR - internal delegate void XmlElementEventHandler(object sender, XmlElementEventArgs e); -#else public delegate void XmlElementEventHandler(object sender, XmlElementEventArgs e); -#endif /// <include file='doc\_Events.uex' path='docs/doc[@for="XmlElementEventArgs"]/*' /> -#if XMLSERIALIZERGENERATOR - internal class XmlElementEventArgs : EventArgs -#else public class XmlElementEventArgs : EventArgs -#endif { private object _o; private XmlElement _elem; @@ -173,22 +153,14 @@ namespace System.Xml.Serialization /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal delegate void XmlNodeEventHandler(object sender, XmlNodeEventArgs e); -#else public delegate void XmlNodeEventHandler(object sender, XmlNodeEventArgs e); -#endif /// <include file='doc\_Events.uex' path='docs/doc[@for="XmlNodeEventArgs"]/*' /> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> -#if XMLSERIALIZERGENERATOR - internal class XmlNodeEventArgs : EventArgs -#else public class XmlNodeEventArgs : EventArgs -#endif { private object _o; private XmlNode _xmlNode; @@ -283,18 +255,10 @@ namespace System.Xml.Serialization } /// <include file='doc\_Events.uex' path='docs/doc[@for="UnreferencedObjectEventHandler"]/*' /> -#if XMLSERIALIZERGENERATOR - internal delegate void UnreferencedObjectEventHandler(object sender, UnreferencedObjectEventArgs e); -#else public delegate void UnreferencedObjectEventHandler(object sender, UnreferencedObjectEventArgs e); -#endif /// <include file='doc\_Events.uex' path='docs/doc[@for="UnreferencedObjectEventArgs"]/*' /> -#if XMLSERIALIZERGENERATOR - internal class UnreferencedObjectEventArgs : EventArgs -#else public class UnreferencedObjectEventArgs : EventArgs -#endif { private object _o; private string _id; diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/indentedWriter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/indentedWriter.cs index 259bc740d8..4bcd9d8ff0 100644 --- a/src/System.Private.Xml/src/System/Xml/Serialization/indentedWriter.cs +++ b/src/System.Private.Xml/src/System/Xml/Serialization/indentedWriter.cs @@ -2,8 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#if XMLSERIALIZERGENERATOR -namespace Microsoft.XmlSerializer.Generator +#if !FEATURE_SERIALIZATION_UAPAOT +namespace System.Xml.Serialization { using System.IO; @@ -74,4 +74,4 @@ namespace Microsoft.XmlSerializer.Generator } } } -#endif
\ No newline at end of file +#endif diff --git a/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs b/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs index 1cf0d23b3c..9ecde4baf1 100644 --- a/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs +++ b/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.RuntimeOnly.cs @@ -865,15 +865,6 @@ public static partial class XmlSerializerTests } [Fact] - public static void Xml_TypeWithMismatchBetweenAttributeAndPropertyType() - { - var value = new TypeWithMismatchBetweenAttributeAndPropertyType(); - var actual = SerializeAndDeserialize(value, -@"<?xml version=""1.0""?><RootElement xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" IntValue=""120"" />"); - Assert.StrictEqual(value.IntValue, actual.IntValue); - } - - [Fact] public static void Xml_TypeWithNestedPublicType() { var value = new List<TypeWithNestedPublicType.LevelData>(); diff --git a/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs b/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs index 821329e542..10281561d3 100644 --- a/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs +++ b/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs @@ -1613,6 +1613,15 @@ string.Format(@"<?xml version=""1.0"" encoding=""utf-8""?> Assert.Equal(value, actual); } + [Fact] + public static void Xml_TypeWithMismatchBetweenAttributeAndPropertyType() + { + var value = new TypeWithMismatchBetweenAttributeAndPropertyType(); + var actual = SerializeAndDeserialize(value, +@"<?xml version=""1.0""?><RootElement xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" IntValue=""120"" />"); + Assert.StrictEqual(value.IntValue, actual.IntValue); + } + private static readonly string s_defaultNs = "http://tempuri.org/"; private static T RoundTripWithXmlMembersMapping<T>(object requestBodyValue, string memberName, string baseline, bool skipStringCompare = false, string wrapperName = null) { |