From b0dc0da5588daf6ddf5dbad1e53ce30b769d96f8 Mon Sep 17 00:00:00 2001 From: Dmitry Kolchev Date: Thu, 29 Aug 2019 23:24:07 +0300 Subject: [PATCH] Add project files. --- Compat.Private.Serialization/CodeObject.cs | 26 + .../CodeTypeReference.cs | 409 ++ .../CodeTypeReferenceCollection.cs | 80 + .../Compat.Private.Serialization.csproj | 25 + Compat.Private.Serialization/Compat/Fx.cs | 43 + .../Compat/Runtime/FatalException.cs | 27 + .../Compat/Runtime/HashHelper.cs | 115 + .../Runtime/Serialization/Attributes.cs | 161 + .../Serialization/ClassDataContract.cs | 1567 +++++++ .../Runtime/Serialization/ClassDataNode.cs | 26 + .../Runtime/Serialization/CodeGenerator.cs | 2360 ++++++++++ .../Serialization/CollectionDataContract.cs | 1343 ++++++ .../Serialization/CollectionDataNode.cs | 57 + .../Runtime/Serialization/DataContract.cs | 2481 ++++++++++ .../Serialization/DataContractPairKey.cs | 30 + .../Serialization/DataContractSerializer.cs | 522 +++ .../DataContractSerializerSettings.cs | 55 + .../Runtime/Serialization/DataContractSet.cs | 548 +++ .../DataContractSurrogateCaller.cs | 80 + .../Runtime/Serialization/DataMember.cs | 295 ++ .../Runtime/Serialization/DataNode`1.cs | 132 + .../Serialization/DateTimeOffsetAdapter.cs | 70 + .../Serialization/DiagnosticUtility.cs | 27 + .../Serialization/DictionaryGlobals.cs | 178 + .../Runtime/Serialization/ElementData.cs | 53 + .../Runtime/Serialization/EnumDataContract.cs | 508 +++ .../Runtime/Serialization/ExportOptions.cs | 38 + .../Serialization/ExtensionDataMember.cs | 13 + .../Serialization/ExtensionDataObject.cs | 13 + .../Serialization/ExtensionDataReader.cs | 877 ++++ .../Runtime/Serialization/GenericInfo.cs | 120 + .../Serialization/GenericNameProvider.cs | 109 + .../GenericParameterDataContract.cs | 39 + .../Compat/Runtime/Serialization/Globals.cs | 1445 ++++++ .../Serialization/HybridObjectCache.cs | 70 + .../Serialization/IDataContractSurrogate.cs | 17 + .../Compat/Runtime/Serialization/IDataNode.cs | 21 + .../Serialization/ISerializableDataMember.cs | 9 + .../Serialization/ISerializableDataNode.cs | 51 + .../Compat/Runtime/Serialization/IntRef.cs | 15 + .../KnownTypeDataContractResolver.cs | 58 + .../NetDataContractSerializer.cs | 599 +++ .../Serialization/ObjectReferenceStack.cs | 114 + .../Runtime/Serialization/ObjectToIdCache.cs | 219 + .../Serialization/PrimitiveDataContract.cs | 837 ++++ .../Runtime/Serialization/SchemaExporter.cs | 1194 +++++ .../Runtime/Serialization/SchemaHelper.cs | 246 + .../Runtime/Serialization/SchemaImporter.cs | 1777 ++++++++ .../Runtime/Serialization/ScopedKnownTypes.cs | 46 + .../Serialization/SerializationMode.cs | 8 + .../Serialization/SerializationTrace.cs | 33 + .../Serialization/SpecialTypeDataContract.cs | 34 + .../Serialization/SurrogateDataContract.cs | 94 + .../Runtime/Serialization/TypeHandleRef.cs | 24 + .../TypeHandleRefEqualityComparer.cs | 17 + .../Runtime/Serialization/TypeInformation.cs | 22 + .../Runtime/Serialization/XmlConverter.cs | 1359 ++++++ .../Runtime/Serialization/XmlDataContract.cs | 370 ++ .../Runtime/Serialization/XmlDataNode.cs | 43 + .../XmlFormatGeneratorStatics.cs | 1405 ++++++ .../Serialization/XmlFormatReaderGenerator.cs | 902 ++++ .../Serialization/XmlFormatWriterGenerator.cs | 743 +++ .../Serialization/XmlObjectSerializer.cs | 418 ++ .../XmlObjectSerializerContext.cs | 342 ++ .../XmlObjectSerializerReadContext.cs | 1225 +++++ .../XmlObjectSerializerReadContextComplex.cs | 533 +++ .../XmlObjectSerializerWriteContext.cs | 863 ++++ .../XmlObjectSerializerWriteContextComplex.cs | 406 ++ .../Serialization/XmlReaderDelegator.cs | 1224 +++++ .../Serialization/XmlSerializableReader.cs | 199 + .../Serialization/XmlSerializableWriter.cs | 109 + .../Serialization/XmlWriterDelegator.cs | 812 ++++ .../Serialization/XsdDataContractExporter.cs | 387 ++ .../Compat/Text/Base64Encoding.cs | 601 +++ .../Compat/Xml/ArrayHelper.cs | 422 ++ .../Compat/Xml/XmlExceptionHelper.cs | 288 ++ .../Resources/Common/SR.Designer.cs | 3996 +++++++++++++++++ .../Resources/Common/SR.cs | 136 + .../Resources/SR.resx | 1431 ++++++ NetDataContractSerializer.sln | 123 + 80 files changed, 37714 insertions(+) create mode 100644 Compat.Private.Serialization/CodeObject.cs create mode 100644 Compat.Private.Serialization/CodeTypeReference.cs create mode 100644 Compat.Private.Serialization/CodeTypeReferenceCollection.cs create mode 100644 Compat.Private.Serialization/Compat.Private.Serialization.csproj create mode 100644 Compat.Private.Serialization/Compat/Fx.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/FatalException.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/HashHelper.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/Attributes.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataNode.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/CodeGenerator.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataNode.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractPairKey.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializer.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializerSettings.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSet.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSurrogateCaller.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataMember.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DataNode`1.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DateTimeOffsetAdapter.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DiagnosticUtility.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/DictionaryGlobals.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ElementData.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/EnumDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ExportOptions.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataMember.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataObject.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataReader.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/GenericInfo.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/GenericNameProvider.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/GenericParameterDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/Globals.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/HybridObjectCache.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/IDataContractSurrogate.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/IDataNode.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataMember.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataNode.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/IntRef.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/KnownTypeDataContractResolver.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/NetDataContractSerializer.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectReferenceStack.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectToIdCache.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/PrimitiveDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaExporter.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaHelper.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaImporter.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/ScopedKnownTypes.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationMode.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationTrace.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SpecialTypeDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/SurrogateDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRef.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRefEqualityComparer.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/TypeInformation.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlConverter.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataContract.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataNode.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatGeneratorStatics.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatReaderGenerator.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatWriterGenerator.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializer.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerContext.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContext.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContext.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlReaderDelegator.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableReader.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableWriter.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XmlWriterDelegator.cs create mode 100644 Compat.Private.Serialization/Compat/Runtime/Serialization/XsdDataContractExporter.cs create mode 100644 Compat.Private.Serialization/Compat/Text/Base64Encoding.cs create mode 100644 Compat.Private.Serialization/Compat/Xml/ArrayHelper.cs create mode 100644 Compat.Private.Serialization/Compat/Xml/XmlExceptionHelper.cs create mode 100644 Compat.Private.Serialization/Resources/Common/SR.Designer.cs create mode 100644 Compat.Private.Serialization/Resources/Common/SR.cs create mode 100644 Compat.Private.Serialization/Resources/SR.resx create mode 100644 NetDataContractSerializer.sln diff --git a/Compat.Private.Serialization/CodeObject.cs b/Compat.Private.Serialization/CodeObject.cs new file mode 100644 index 0000000..fc4e4e0 --- /dev/null +++ b/Compat.Private.Serialization/CodeObject.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Specialized; + +#if !FEATURE_SERIALIZATION +namespace System.CodeDom +#else +namespace Compat.Runtime.Serialization +#endif +{ +#if !FEATURE_SERIALIZATION + public class CodeObject +#else + internal class CodeObject +#endif + { + private IDictionary _userData = null; + + public CodeObject() { } + + public IDictionary UserData => _userData ?? (_userData = new ListDictionary()); + } +} diff --git a/Compat.Private.Serialization/CodeTypeReference.cs b/Compat.Private.Serialization/CodeTypeReference.cs new file mode 100644 index 0000000..86ce3af --- /dev/null +++ b/Compat.Private.Serialization/CodeTypeReference.cs @@ -0,0 +1,409 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +#if !FEATURE_SERIALIZATION +namespace System.CodeDom +#else +namespace Compat.Runtime.Serialization +#endif +{ + [Flags] +#if !FEATURE_SERIALIZATION + public enum CodeTypeReferenceOptions +#else + internal enum CodeTypeReferenceOptions +#endif + { + GlobalReference = 0x00000001, + GenericTypeParameter = 0x00000002 + } + +#if !FEATURE_SERIALIZATION + public class CodeTypeReference : CodeObject +#else + internal class CodeTypeReference : CodeObject +#endif + { + private string _baseType; + private readonly bool _isInterface; + private CodeTypeReferenceCollection _typeArguments; + private bool _needsFixup = false; + + public CodeTypeReference() + { + _baseType = string.Empty; + ArrayRank = 0; + ArrayElementType = null; + } + + public CodeTypeReference(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (type.IsArray) + { + ArrayRank = type.GetArrayRank(); + ArrayElementType = new CodeTypeReference(type.GetElementType()); + _baseType = null; + } + else + { + InitializeFromType(type); + ArrayRank = 0; + ArrayElementType = null; + } + + _isInterface = type.IsInterface; + } + + public CodeTypeReference(Type type, CodeTypeReferenceOptions codeTypeReferenceOption) : this(type) + { + Options = codeTypeReferenceOption; + } + + public CodeTypeReference(string typeName, CodeTypeReferenceOptions codeTypeReferenceOption) + { + Initialize(typeName, codeTypeReferenceOption); + } + + public CodeTypeReference(string typeName) + { + Initialize(typeName); + } + + private void InitializeFromType(Type type) + { + _baseType = type.Name; + if (!type.IsGenericParameter) + { + Type currentType = type; + while (currentType.IsNested) + { + currentType = currentType.DeclaringType; + _baseType = currentType.Name + "+" + _baseType; + } + + if (!string.IsNullOrEmpty(type.Namespace)) + { + _baseType = type.Namespace + "." + _baseType; + } + } + + // pick up the type arguments from an instantiated generic type but not an open one + if (type.IsGenericType && !type.ContainsGenericParameters) + { + Type[] genericArgs = type.GetGenericArguments(); + for (int i = 0; i < genericArgs.Length; i++) + { + TypeArguments.Add(new CodeTypeReference(genericArgs[i])); + } + } + else if (!type.IsGenericTypeDefinition) + { + // if the user handed us a non-generic type, but later + // appends generic type arguments, we'll pretend + // it's a generic type for their sake - this is good for + // them if they pass in System.Nullable class when they + // meant the System.Nullable value type. + _needsFixup = true; + } + } + + private void Initialize(string typeName) + { + Initialize(typeName, Options); + } + + private void Initialize(string typeName, CodeTypeReferenceOptions options) + { + Options = options; + if (string.IsNullOrEmpty(typeName)) + { + typeName = typeof(void).FullName; + _baseType = typeName; + ArrayRank = 0; + ArrayElementType = null; + return; + } + + typeName = RipOffAssemblyInformationFromTypeName(typeName); + + int end = typeName.Length - 1; + int current = end; + _needsFixup = true; // default to true, and if we find arity or generic type args, we'll clear the flag. + + // Scan the entire string for valid array tails and store ranks for array tails + // we found in a queue. + var q = new Queue(); + while (current >= 0) + { + int rank = 1; + if (typeName[current--] == ']') + { + while (current >= 0 && typeName[current] == ',') + { + rank++; + current--; + } + + if (current >= 0 && typeName[current] == '[') + { + // found a valid array tail + q.Enqueue(rank); + current--; + end = current; + continue; + } + } + break; + } + + // Try find generic type arguments + current = end; + var typeArgumentList = new List(); + var subTypeNames = new Stack(); + if (current > 0 && typeName[current--] == ']') + { + _needsFixup = false; + int unmatchedRightBrackets = 1; + int subTypeNameEndIndex = end; + + // Try find the matching '[', if we can't find it, we will not try to parse the string + while (current >= 0) + { + if (typeName[current] == '[') + { + // break if we found matched brackets + if (--unmatchedRightBrackets == 0) break; + } + else if (typeName[current] == ']') + { + ++unmatchedRightBrackets; + } + else if (typeName[current] == ',' && unmatchedRightBrackets == 1) + { + // + // Type name can contain nested generic types. Following is an example: + // System.Collections.Generic.Dictionary`2[[System.string, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], + // [System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], + // mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] + // + // Spliltting by ',' won't work. We need to do first-level split by ','. + // + if (current + 1 < subTypeNameEndIndex) + { + subTypeNames.Push(typeName.Substring(current + 1, subTypeNameEndIndex - current - 1)); + } + + subTypeNameEndIndex = current; + } + --current; + } + + if (current > 0 && (end - current - 1) > 0) + { + // push the last generic type argument name if there is any + if (current + 1 < subTypeNameEndIndex) + { + subTypeNames.Push(typeName.Substring(current + 1, subTypeNameEndIndex - current - 1)); + } + + // we found matched brackets and the brackets contains some characters. + while (subTypeNames.Count > 0) + { + string name = RipOffAssemblyInformationFromTypeName(subTypeNames.Pop()); + typeArgumentList.Add(new CodeTypeReference(name)); + } + end = current - 1; + } + } + + if (end < 0) + { + // this can happen if we have some string like "[...]" + _baseType = typeName; + return; + } + + if (q.Count > 0) + { + CodeTypeReference type = new CodeTypeReference(typeName.Substring(0, end + 1), Options); + + for (int i = 0; i < typeArgumentList.Count; i++) + { + type.TypeArguments.Add(typeArgumentList[i]); + } + + while (q.Count > 1) + { + type = new CodeTypeReference(type, q.Dequeue()); + } + + // we don't need to create a new CodeTypeReference for the last one. + Debug.Assert(q.Count == 1, "We should have one and only one in the rank queue."); + _baseType = null; + ArrayRank = q.Dequeue(); + ArrayElementType = type; + } + else if (typeArgumentList.Count > 0) + { + for (int i = 0; i < typeArgumentList.Count; i++) + { + TypeArguments.Add(typeArgumentList[i]); + } + + _baseType = typeName.Substring(0, end + 1); + } + else + { + _baseType = typeName; + } + + // Now see if we have some arity. baseType could be null if this is an array type. + if (_baseType != null && _baseType.IndexOf('`') != -1) // string.Contains(char) is .NetCore2.1+ specific + { + _needsFixup = false; + } + } + + public CodeTypeReference(string typeName, params CodeTypeReference[] typeArguments) : this(typeName) + { + if (typeArguments != null && typeArguments.Length > 0) + { + TypeArguments.AddRange(typeArguments); + } + } + +#if !FEATURE_SERIALIZATION + public CodeTypeReference(CodeTypeParameter typeParameter) : + this(typeParameter?.Name) + { + Options = CodeTypeReferenceOptions.GenericTypeParameter; + } +#endif + + public CodeTypeReference(string baseType, int rank) + { + _baseType = null; + ArrayRank = rank; + ArrayElementType = new CodeTypeReference(baseType); + } + + public CodeTypeReference(CodeTypeReference arrayType, int rank) + { + _baseType = null; + ArrayRank = rank; + ArrayElementType = arrayType; + } + + public CodeTypeReference ArrayElementType { get; set; } + + public int ArrayRank { get; set; } + + internal int NestedArrayDepth => ArrayElementType == null ? 0 : 1 + ArrayElementType.NestedArrayDepth; + + public string BaseType + { + get + { + if (ArrayRank > 0 && ArrayElementType != null) + { + return ArrayElementType.BaseType; + } + + if (string.IsNullOrEmpty(_baseType)) + { + return string.Empty; + } + + string returnType = _baseType; + return _needsFixup && TypeArguments.Count > 0 ? + returnType + '`' + TypeArguments.Count.ToString(CultureInfo.InvariantCulture) : + returnType; + } + set + { + _baseType = value; + Initialize(_baseType); + } + } + + public CodeTypeReferenceOptions Options { get; set; } + + public CodeTypeReferenceCollection TypeArguments + { + get + { + if (ArrayRank > 0 && ArrayElementType != null) + { + return ArrayElementType.TypeArguments; + } + + if (_typeArguments == null) + { + _typeArguments = new CodeTypeReferenceCollection(); + } + + return _typeArguments; + } + } + + internal bool IsInterface => _isInterface; // Note that this only works correctly if the Type ctor was used. Otherwise, it's always false. + + // + // The string for generic type argument might contain assembly information and square bracket pair. + // There might be leading spaces in front the type name. + // Following function will rip off assembly information and brackets + // Following is an example: + // " [System.Collections.Generic.List[[System.string, mscorlib, Version=2.0.0.0, Culture=neutral, + // PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]" + // + private string RipOffAssemblyInformationFromTypeName(string typeName) + { + int start = 0; + int end = typeName.Length - 1; + string result = typeName; + + // skip whitespace in the beginning + while (start < typeName.Length && char.IsWhiteSpace(typeName[start])) start++; + while (end >= 0 && char.IsWhiteSpace(typeName[end])) end--; + + if (start < end) + { + if (typeName[start] == '[' && typeName[end] == ']') + { + start++; + end--; + } + + // if we still have a ] at the end, there's no assembly info. + if (typeName[end] != ']') + { + int commaCount = 0; + for (int index = end; index >= start; index--) + { + if (typeName[index] == ',') + { + commaCount++; + if (commaCount == 4) + { + result = typeName.Substring(start, index - start); + break; + } + } + } + } + } + + return result; + } + } +} diff --git a/Compat.Private.Serialization/CodeTypeReferenceCollection.cs b/Compat.Private.Serialization/CodeTypeReferenceCollection.cs new file mode 100644 index 0000000..b61fcca --- /dev/null +++ b/Compat.Private.Serialization/CodeTypeReferenceCollection.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections; + +#if !FEATURE_SERIALIZATION +namespace System.CodeDom +#else +namespace Compat.Runtime.Serialization +#endif +{ +#if !FEATURE_SERIALIZATION + public class CodeTypeReferenceCollection : CollectionBase +#else + internal class CodeTypeReferenceCollection : CollectionBase +#endif + { + public CodeTypeReferenceCollection() { } + + public CodeTypeReferenceCollection(CodeTypeReferenceCollection value) + { + AddRange(value); + } + + public CodeTypeReferenceCollection(CodeTypeReference[] value) + { + AddRange(value); + } + + public CodeTypeReference this[int index] + { + get { return ((CodeTypeReference)(List[index])); } + set { List[index] = value; } + } + + public int Add(CodeTypeReference value) => List.Add(value); + + public void Add(string value) => Add(new CodeTypeReference(value)); + + public void Add(Type value) => Add(new CodeTypeReference(value)); + + public void AddRange(CodeTypeReference[] value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + for (int i = 0; i < value.Length; i++) + { + Add(value[i]); + } + } + + public void AddRange(CodeTypeReferenceCollection value) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + int currentCount = value.Count; + for (int i = 0; i < currentCount; i++) + { + Add(value[i]); + } + } + + public bool Contains(CodeTypeReference value) => List.Contains(value); + + public void CopyTo(CodeTypeReference[] array, int index) => List.CopyTo(array, index); + + public int IndexOf(CodeTypeReference value) => List.IndexOf(value); + + public void Insert(int index, CodeTypeReference value) => List.Insert(index, value); + + public void Remove(CodeTypeReference value) => List.Remove(value); + } +} diff --git a/Compat.Private.Serialization/Compat.Private.Serialization.csproj b/Compat.Private.Serialization/Compat.Private.Serialization.csproj new file mode 100644 index 0000000..bb42222 --- /dev/null +++ b/Compat.Private.Serialization/Compat.Private.Serialization.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + 8.0 + + + + + true + TRACE;FEATURE_SERIALIZATION + + + + + + + + + Compat + + + + + diff --git a/Compat.Private.Serialization/Compat/Fx.cs b/Compat.Private.Serialization/Compat/Fx.cs new file mode 100644 index 0000000..e58e97a --- /dev/null +++ b/Compat.Private.Serialization/Compat/Fx.cs @@ -0,0 +1,43 @@ +using System; +using System.Diagnostics; + +namespace Compat +{ + internal class Fx + { + public static void Assert(string message) + { + Debug.Assert(false, message); + } + + public static void Assert(bool condition, string message) + { + Debug.Assert(condition, message); + } + + public static bool IsFatal(Exception ex) + { + ex = Unwrap(ex); + + return ex is NullReferenceException || + ex is StackOverflowException || + ex is OutOfMemoryException || + ex is System.Threading.ThreadAbortException || + ex is System.Runtime.InteropServices.SEHException || + ex is System.Security.SecurityException; + } + + internal static Exception Unwrap(Exception ex) + { + // for certain types of exceptions, we care more about the inner + // exception + while (ex.InnerException != null && + (ex is System.Reflection.TargetInvocationException)) + { + ex = ex.InnerException; + } + + return ex; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/FatalException.cs b/Compat.Private.Serialization/Compat/Runtime/FatalException.cs new file mode 100644 index 0000000..7acc467 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/FatalException.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; + +namespace Compat.Runtime +{ + [Serializable] + internal class FatalException : SystemException + { + public FatalException() + { + } + public FatalException(string message) : base(message) + { + } + + public FatalException(string message, Exception innerException) : base(message, innerException) + { + // This can't throw something like ArgumentException because that would be worse than + // throwing the fatal exception that was requested. + Fx.Assert(innerException == null || !Fx.IsFatal(innerException), "FatalException can't be used to wrap fatal exceptions."); + } + + protected FatalException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/HashHelper.cs b/Compat.Private.Serialization/Compat/Runtime/HashHelper.cs new file mode 100644 index 0000000..f4531e3 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/HashHelper.cs @@ -0,0 +1,115 @@ +namespace Compat.Runtime +{ + internal static class HashHelper + { + // "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" + // DO NOT USE FOR SECURITY PURPOSES. + public static byte[] ComputeHash(byte[] buffer) + { + int[] shifts = new int[] { 7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21 }; + uint[] sines = new uint[] { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; + + int blocks = (buffer.Length + 8) / 64 + 1; + + uint aa = 0x67452301; + uint bb = 0xefcdab89; + uint cc = 0x98badcfe; + uint dd = 0x10325476; + + for (int i = 0; i < blocks; i++) + { + byte[] block = buffer; + int offset = i * 64; + + if (offset + 64 > buffer.Length) + { + block = new byte[64]; + + for (int j = offset; j < buffer.Length; j++) + { + block[j - offset] = buffer[j]; + } + if (offset <= buffer.Length) + { + block[buffer.Length - offset] = 0x80; + } + if (i == blocks - 1) + { + block[56] = (byte)(buffer.Length << 3); + block[57] = (byte)(buffer.Length >> 5); + block[58] = (byte)(buffer.Length >> 13); + block[59] = (byte)(buffer.Length >> 21); + } + + offset = 0; + } + + uint a = aa; + uint b = bb; + uint c = cc; + uint d = dd; + + uint f; + int g; + + for (int j = 0; j < 64; j++) + { + if (j < 16) + { + f = b & c | ~b & d; + g = j; + } + else if (j < 32) + { + f = b & d | c & ~d; + g = 5 * j + 1; + } + else if (j < 48) + { + f = b ^ c ^ d; + g = 3 * j + 5; + } + else + { + f = c ^ (b | ~d); + g = 7 * j; + } + + g = (g & 0x0f) * 4 + offset; + + uint hold = d; + d = c; + c = b; + + b = a + f + sines[j] + (uint)(block[g] + (block[g + 1] << 8) + (block[g + 2] << 16) + (block[g + 3] << 24)); + b = b << shifts[j & 3 | j >> 2 & ~3] | b >> 32 - shifts[j & 3 | j >> 2 & ~3]; + b += c; + + a = hold; + } + + aa += a; + bb += b; + cc += c; + dd += d; + } + + return new byte[] { + (byte)aa, (byte)(aa >> 8), (byte)(aa >> 16), (byte)(aa >> 24), + (byte)bb, (byte)(bb >> 8), (byte)(bb >> 16), (byte)(bb >> 24), + (byte)cc, (byte)(cc >> 8), (byte)(cc >> 16), (byte)(cc >> 24), + (byte)dd, (byte)(dd >> 8), (byte)(dd >> 16), (byte)(dd >> 24) }; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/Attributes.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/Attributes.cs new file mode 100644 index 0000000..fec8fad --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/Attributes.cs @@ -0,0 +1,161 @@ +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal class Attributes + { + private static readonly XmlDictionaryString[] serializationLocalNames; + + private static readonly XmlDictionaryString[] schemaInstanceLocalNames; + + static Attributes() + { + serializationLocalNames = new XmlDictionaryString[] + { + DictionaryGlobals.IdLocalName, + DictionaryGlobals.ArraySizeLocalName, + DictionaryGlobals.RefLocalName, + DictionaryGlobals.ClrTypeLocalName, + DictionaryGlobals.ClrAssemblyLocalName, + DictionaryGlobals.ISerializableFactoryTypeLocalName + }; + + schemaInstanceLocalNames = new XmlDictionaryString[] + { + DictionaryGlobals.XsiNilLocalName, + DictionaryGlobals.XsiTypeLocalName + }; + } + + internal string Id; + internal string Ref; + internal string XsiTypeName; + internal string XsiTypeNamespace; + internal string XsiTypePrefix; + internal bool XsiNil; + internal string ClrAssembly; + internal string ClrType; + internal int ArraySZSize; + internal string FactoryTypeName; + internal string FactoryTypeNamespace; + internal string FactoryTypePrefix; + internal bool UnrecognizedAttributesFound; + + internal void Read(XmlReaderDelegator reader) + { + Reset(); + + while (reader.MoveToNextAttribute()) + { + switch (reader.IndexOfLocalName(serializationLocalNames, DictionaryGlobals.SerializationNamespace)) + { + case 0: + ReadId(reader); + break; + case 1: + ReadArraySize(reader); + break; + case 2: + ReadRef(reader); + break; + case 3: + ClrType = reader.Value; + break; + case 4: + ClrAssembly = reader.Value; + break; + case 5: + ReadFactoryType(reader); + break; + default: + switch (reader.IndexOfLocalName(schemaInstanceLocalNames, DictionaryGlobals.SchemaInstanceNamespace)) + { + case 0: + ReadXsiNil(reader); + break; + case 1: + ReadXsiType(reader); + break; + default: + if (!reader.IsNamespaceUri(DictionaryGlobals.XmlnsNamespace)) + { + UnrecognizedAttributesFound = true; + } + + break; + } + break; + } + } + reader.MoveToElement(); + } + + internal void Reset() + { + Id = Globals.NewObjectId; + Ref = Globals.NewObjectId; + XsiTypeName = null; + XsiTypeNamespace = null; + XsiTypePrefix = null; + XsiNil = false; + ClrAssembly = null; + ClrType = null; + ArraySZSize = -1; + FactoryTypeName = null; + FactoryTypeNamespace = null; + FactoryTypePrefix = null; + UnrecognizedAttributesFound = false; + } + + private void ReadId(XmlReaderDelegator reader) + { + Id = reader.ReadContentAsString(); + if (string.IsNullOrEmpty(Id)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidXsIdDefinition, Id))); + } + } + + private void ReadRef(XmlReaderDelegator reader) + { + Ref = reader.ReadContentAsString(); + if (string.IsNullOrEmpty(Ref)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidXsRefDefinition, Ref))); + } + } + + private void ReadXsiNil(XmlReaderDelegator reader) + { + XsiNil = reader.ReadContentAsBoolean(); + } + + private void ReadArraySize(XmlReaderDelegator reader) + { + ArraySZSize = reader.ReadContentAsInt(); + if (ArraySZSize < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidSizeDefinition, ArraySZSize))); + } + } + + private void ReadXsiType(XmlReaderDelegator reader) + { + string xsiTypeString = reader.Value; + if (xsiTypeString != null && xsiTypeString.Length > 0) + { + XmlObjectSerializerReadContext.ParseQualifiedName(xsiTypeString, reader, out XsiTypeName, out XsiTypeNamespace, out XsiTypePrefix); + } + } + + private void ReadFactoryType(XmlReaderDelegator reader) + { + string factoryTypeString = reader.Value; + if (factoryTypeString != null && factoryTypeString.Length > 0) + { + XmlObjectSerializerReadContext.ParseQualifiedName(factoryTypeString, reader, out FactoryTypeName, out FactoryTypeNamespace, out FactoryTypePrefix); + } + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataContract.cs new file mode 100644 index 0000000..eb82793 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataContract.cs @@ -0,0 +1,1567 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Security; +using System.Threading; +using System.Xml; +using DataContractAttribute = System.Runtime.Serialization.DataContractAttribute; +using DataMemberAttribute = System.Runtime.Serialization.DataMemberAttribute; +using IgnoreDataMemberAttribute = System.Runtime.Serialization.IgnoreDataMemberAttribute; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; +using SerializationInfo = System.Runtime.Serialization.SerializationInfo; +using StreamingContext = System.Runtime.Serialization.StreamingContext; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + internal sealed class ClassDataContract : DataContract + { + public XmlDictionaryString[] ContractNamespaces; + + public XmlDictionaryString[] MemberNames; + + public XmlDictionaryString[] MemberNamespaces; + + private XmlDictionaryString[] childElementNamespaces; + + private ClassDataContractCriticalHelper helper; + + internal ClassDataContract() + : base(new ClassDataContractCriticalHelper()) + { + InitClassDataContract(); + } + + internal ClassDataContract(Type type) + : base(new ClassDataContractCriticalHelper(type)) + { + InitClassDataContract(); + } + + private ClassDataContract(Type type, XmlDictionaryString ns, string[] memberNames) + : base(new ClassDataContractCriticalHelper(type, ns, memberNames)) + { + InitClassDataContract(); + } + + private void InitClassDataContract() + { + helper = base.Helper as ClassDataContractCriticalHelper; + ContractNamespaces = helper.ContractNamespaces; + MemberNames = helper.MemberNames; + MemberNamespaces = helper.MemberNamespaces; + } + + internal ClassDataContract BaseContract + { + get => helper.BaseContract; + set => helper.BaseContract = value; + } + + internal List Members + { + get => helper.Members; + set => helper.Members = value; + } + + public XmlDictionaryString[] ChildElementNamespaces + { + get + { + if (childElementNamespaces == null) + { + lock (this) + { + if (childElementNamespaces == null) + { + if (helper.ChildElementNamespaces == null) + { + XmlDictionaryString[] tempChildElementamespaces = CreateChildElementNamespaces(); + Thread.MemoryBarrier(); + helper.ChildElementNamespaces = tempChildElementamespaces; + } + childElementNamespaces = helper.ChildElementNamespaces; + } + } + } + return childElementNamespaces; + } + } + + internal MethodInfo OnSerializing => helper.OnSerializing; + + internal MethodInfo OnSerialized => helper.OnSerialized; + + internal MethodInfo OnDeserializing => helper.OnDeserializing; + + internal MethodInfo OnDeserialized => helper.OnDeserialized; + + internal MethodInfo ExtensionDataSetMethod => helper.ExtensionDataSetMethod; + + internal override DataContractDictionary KnownDataContracts + { + get => helper.KnownDataContracts; + set => helper.KnownDataContracts = value; + } + + internal override bool IsISerializable + { + get => helper.IsISerializable; + set => helper.IsISerializable = value; + } + + internal bool IsNonAttributedType => helper.IsNonAttributedType; + + internal bool HasDataContract => helper.HasDataContract; + + internal bool HasExtensionData => helper.HasExtensionData; + + internal string SerializationExceptionMessage => helper.SerializationExceptionMessage; + + internal string DeserializationExceptionMessage => helper.DeserializationExceptionMessage; + + internal bool IsReadOnlyContract => DeserializationExceptionMessage != null; + + internal ConstructorInfo GetISerializableConstructor() + { + return helper.GetISerializableConstructor(); + } + + internal ConstructorInfo GetNonAttributedTypeConstructor() + { + return helper.GetNonAttributedTypeConstructor(); + } + + internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate + { + get + { + if (helper.XmlFormatWriterDelegate == null) + { + lock (this) + { + if (helper.XmlFormatWriterDelegate == null) + { + XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this); + Thread.MemoryBarrier(); + helper.XmlFormatWriterDelegate = tempDelegate; + } + } + } + return helper.XmlFormatWriterDelegate; + } + } + + internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate + { + get + { + if (helper.XmlFormatReaderDelegate == null) + { + lock (this) + { + if (helper.XmlFormatReaderDelegate == null) + { + if (IsReadOnlyContract) + { + ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/); + } + XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this); + Thread.MemoryBarrier(); + helper.XmlFormatReaderDelegate = tempDelegate; + } + } + } + return helper.XmlFormatReaderDelegate; + } + } + + internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames) + { + return new ClassDataContract(type, ns, memberNames); + } + + internal static void CheckAndAddMember(List members, DataMember memberContract, Dictionary memberNamesTable) + { + if (memberNamesTable.TryGetValue(memberContract.Name, out DataMember existingMemberContract)) + { + Type declaringType = memberContract.MemberInfo.DeclaringType; + DataContract.ThrowInvalidDataContractException( + SR.Format((declaringType.IsEnum ? SR.DupEnumMemberValue : SR.DupMemberName), + existingMemberContract.MemberInfo.Name, + memberContract.MemberInfo.Name, + DataContract.GetClrTypeFullName(declaringType), + memberContract.Name), + declaringType); + } + memberNamesTable.Add(memberContract.Name, memberContract); + members.Add(memberContract); + } + + internal static XmlDictionaryString GetChildNamespaceToDeclare(DataContract dataContract, Type childType, XmlDictionary dictionary) + { + childType = DataContract.UnwrapNullableType(childType); + if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType) + && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull) + { + string ns = DataContract.GetStableName(childType).Namespace; + if (ns.Length > 0 && ns != dataContract.Namespace.Value) + { + return dictionary.Add(ns); + } + } + return null; + } + + // check whether a corresponding update is required in DataContractCriticalHelper.CreateDataContract + internal static bool IsNonAttributedTypeValidForSerialization(Type type) + { + if (type.IsArray) + { + return false; + } + + if (type.IsEnum) + { + return false; + } + + if (type.IsGenericParameter) + { + return false; + } + + if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) + { + return false; + } + + if (type.IsPointer) + { + return false; + } + + if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) + { + return false; + } + + Type[] interfaceTypes = type.GetInterfaces(); + foreach (Type interfaceType in interfaceTypes) + { + if (CollectionDataContract.IsCollectionInterface(interfaceType)) + { + return false; + } + } + + if (type.IsSerializable) + { + return false; + } + + if (Globals.TypeOfISerializable.IsAssignableFrom(type)) + { + return false; + } + + if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) + { + return false; + } + + if (type == Globals.TypeOfExtensionDataObject) + { + return false; + } + + if (type.IsValueType) + { + return type.IsVisible; + } + else + { + return (type.IsVisible && + type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null) != null); + } + } + + private XmlDictionaryString[] CreateChildElementNamespaces() + { + if (Members == null) + { + return null; + } + + XmlDictionaryString[] baseChildElementNamespaces = null; + if (BaseContract != null) + { + baseChildElementNamespaces = BaseContract.ChildElementNamespaces; + } + + int baseChildElementNamespaceCount = (baseChildElementNamespaces != null) ? baseChildElementNamespaces.Length : 0; + XmlDictionaryString[] childElementNamespaces = new XmlDictionaryString[Members.Count + baseChildElementNamespaceCount]; + if (baseChildElementNamespaceCount > 0) + { + Array.Copy(baseChildElementNamespaces, 0, childElementNamespaces, 0, baseChildElementNamespaces.Length); + } + + XmlDictionary dictionary = new XmlDictionary(); + for (int i = 0; i < Members.Count; i++) + { + childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, Members[i].MemberType, dictionary); + } + + return childElementNamespaces; + } + + private void EnsureMethodsImported() + { + helper.EnsureMethodsImported(); + } + + public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + XmlFormatWriterDelegate(xmlWriter, obj, context, this); + } + + public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + { + xmlReader.Read(); + object o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces); + xmlReader.ReadEndElement(); + return o; + } + + internal bool RequiresMemberAccessForRead(SecurityException securityException) + { + EnsureMethodsImported(); + + if (!IsTypeVisible(UnderlyingType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractTypeNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + + if (BaseContract != null && BaseContract.RequiresMemberAccessForRead(securityException)) + { + return true; + } + + if (ConstructorRequiresMemberAccess(GetISerializableConstructor())) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustISerializableNoPublicConstructor, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + + + if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor())) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustNonAttributedSerializableTypeNoPublicConstructor, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + + + if (MethodRequiresMemberAccess(OnDeserializing)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractOnDeserializingNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + OnDeserializing.Name), + securityException)); + } + return true; + } + + if (MethodRequiresMemberAccess(OnDeserialized)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractOnDeserializedNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + OnDeserialized.Name), + securityException)); + } + return true; + } + + if (Members != null) + { + for (int i = 0; i < Members.Count; i++) + { + if (Members[i].RequiresMemberAccessForSet()) + { + if (securityException != null) + { + if (Members[i].MemberInfo is FieldInfo) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractFieldSetNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + Members[i].MemberInfo.Name), + securityException)); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractPropertySetNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + Members[i].MemberInfo.Name), + securityException)); + } + } + return true; + } + } + } + + return false; + } + + internal bool RequiresMemberAccessForWrite(SecurityException securityException) + { + EnsureMethodsImported(); + + if (!IsTypeVisible(UnderlyingType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractTypeNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + + if (BaseContract != null && BaseContract.RequiresMemberAccessForWrite(securityException)) + { + return true; + } + + if (MethodRequiresMemberAccess(OnSerializing)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractOnSerializingNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + OnSerializing.Name), + securityException)); + } + return true; + } + + if (MethodRequiresMemberAccess(OnSerialized)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractOnSerializedNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + OnSerialized.Name), + securityException)); + } + return true; + } + + if (Members != null) + { + for (int i = 0; i < Members.Count; i++) + { + if (Members[i].RequiresMemberAccessForGet()) + { + if (securityException != null) + { + if (Members[i].MemberInfo is FieldInfo) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractFieldGetNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + Members[i].MemberInfo.Name), + securityException)); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustDataContractPropertyGetNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + Members[i].MemberInfo.Name), + securityException)); + } + } + return true; + } + } + } + + return false; + } + + private class ClassDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private ClassDataContract baseContract; + private List members; + private MethodInfo onSerializing, onSerialized; + private MethodInfo onDeserializing, onDeserialized; + private MethodInfo extensionDataSetMethod; + private DataContractDictionary knownDataContracts; + private string serializationExceptionMessage; + private bool isISerializable; + private bool isKnownTypeAttributeChecked; + private bool isMethodChecked; + private readonly bool hasExtensionData; + private bool isNonAttributedType; + private bool hasDataContract; + private XmlDictionaryString[] childElementNamespaces; + private XmlFormatClassReaderDelegate xmlFormatReaderDelegate; + private XmlFormatClassWriterDelegate xmlFormatWriterDelegate; + + public XmlDictionaryString[] ContractNamespaces; + public XmlDictionaryString[] MemberNames; + public XmlDictionaryString[] MemberNamespaces; + + internal ClassDataContractCriticalHelper() + : base() + { + } + + internal ClassDataContractCriticalHelper(Type type) + : base(type) + { + XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type); + if (type == Globals.TypeOfDBNull) + { + StableName = stableName; + members = new List(); + XmlDictionary dictionary = new XmlDictionary(2); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); + ContractNamespaces = MemberNames = MemberNamespaces = new XmlDictionaryString[] { }; + EnsureMethodsImported(); + return; + } + Type baseType = type.BaseType; + isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type)); + SetIsNonAttributedType(type); + if (isISerializable) + { + if (HasDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.ISerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type)))); + } + + if (baseType != null && !(baseType.IsSerializable && Globals.TypeOfISerializable.IsAssignableFrom(baseType))) + { + baseType = null; + } + } + IsValueType = type.IsValueType; + if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) + { + DataContract baseContract = DataContract.GetDataContract(baseType); + if (baseContract is CollectionDataContract) + { + BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract; + } + else + { + BaseContract = baseContract as ClassDataContract; + } + + if (BaseContract != null && BaseContract.IsNonAttributedType && !isNonAttributedType) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError + (new InvalidDataContractException(SR.Format(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes, + DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(baseType)))); + } + } + else + { + BaseContract = null; + } + + hasExtensionData = (Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(type)); + if (hasExtensionData && !HasDataContract && !IsNonAttributedType) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.OnlyDataContractTypesCanHaveExtensionData, DataContract.GetClrTypeFullName(type)))); + } + + if (isISerializable) + { + SetDataContractName(stableName); + } + else + { + StableName = stableName; + ImportDataMembers(); + XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); + + int baseMemberCount = 0; + int baseContractCount = 0; + if (BaseContract == null) + { + MemberNames = new XmlDictionaryString[Members.Count]; + MemberNamespaces = new XmlDictionaryString[Members.Count]; + ContractNamespaces = new XmlDictionaryString[1]; + } + else + { + if (BaseContract.IsReadOnlyContract) + { + serializationExceptionMessage = BaseContract.SerializationExceptionMessage; + } + baseMemberCount = BaseContract.MemberNames.Length; + MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount]; + Array.Copy(BaseContract.MemberNames, MemberNames, baseMemberCount); + MemberNamespaces = new XmlDictionaryString[Members.Count + baseMemberCount]; + Array.Copy(BaseContract.MemberNamespaces, MemberNamespaces, baseMemberCount); + baseContractCount = BaseContract.ContractNamespaces.Length; + ContractNamespaces = new XmlDictionaryString[1 + baseContractCount]; + Array.Copy(BaseContract.ContractNamespaces, ContractNamespaces, baseContractCount); + } + ContractNamespaces[baseContractCount] = Namespace; + for (int i = 0; i < Members.Count; i++) + { + MemberNames[i + baseMemberCount] = dictionary.Add(Members[i].Name); + MemberNamespaces[i + baseMemberCount] = Namespace; + } + } + EnsureMethodsImported(); + } + + internal ClassDataContractCriticalHelper(Type type, XmlDictionaryString ns, string[] memberNames) + : base(type) + { + StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value); + ImportDataMembers(); + XmlDictionary dictionary = new XmlDictionary(1 + Members.Count); + Name = dictionary.Add(StableName.Name); + Namespace = ns; + ContractNamespaces = new XmlDictionaryString[] { Namespace }; + MemberNames = new XmlDictionaryString[Members.Count]; + MemberNamespaces = new XmlDictionaryString[Members.Count]; + for (int i = 0; i < Members.Count; i++) + { + Members[i].Name = memberNames[i]; + MemberNames[i] = dictionary.Add(Members[i].Name); + MemberNamespaces[i] = Namespace; + } + EnsureMethodsImported(); + } + + private void EnsureIsReferenceImported(Type type) + { + bool isReference = false; + bool hasDataContractAttribute = TryGetDCAttribute(type, out DataContractAttribute dataContractAttribute); + + if (BaseContract != null) + { + if (hasDataContractAttribute && dataContractAttribute.IsReferenceSetExplicitly) + { + bool baseIsReference = BaseContract.IsReference; + if ((baseIsReference && !dataContractAttribute.IsReference) || + (!baseIsReference && dataContractAttribute.IsReference)) + { + DataContract.ThrowInvalidDataContractException( + SR.Format(SR.InconsistentIsReference, + DataContract.GetClrTypeFullName(type), + dataContractAttribute.IsReference, + DataContract.GetClrTypeFullName(BaseContract.UnderlyingType), + BaseContract.IsReference), + type); + } + else + { + isReference = dataContractAttribute.IsReference; + } + } + else + { + isReference = BaseContract.IsReference; + } + } + else if (hasDataContractAttribute) + { + if (dataContractAttribute.IsReference) + { + isReference = dataContractAttribute.IsReference; + } + } + + if (isReference && type.IsValueType) + { + DataContract.ThrowInvalidDataContractException( + SR.Format(SR.ValueTypeCannotHaveIsReference, + DataContract.GetClrTypeFullName(type), + true, + false), + type); + return; + } + + IsReference = isReference; + } + + private void ImportDataMembers() + { + Type type = UnderlyingType; + EnsureIsReferenceImported(type); + List tempMembers = new List(); + Dictionary memberNamesTable = new Dictionary(); + + MemberInfo[] memberInfos; + if (isNonAttributedType) + { + memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); + } + else + { + memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + } + + for (int i = 0; i < memberInfos.Length; i++) + { + MemberInfo member = memberInfos[i]; + if (HasDataContract) + { + object[] memberAttributes = member.GetCustomAttributes(typeof(DataMemberAttribute), false); + if (memberAttributes != null && memberAttributes.Length > 0) + { + if (memberAttributes.Length > 1) + { + ThrowInvalidDataContractException(SR.Format(SR.TooManyDataMembers, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name)); + } + + DataMember memberContract = new DataMember(member); + + if (member.MemberType == MemberTypes.Property) + { + PropertyInfo property = (PropertyInfo)member; + + MethodInfo getMethod = property.GetGetMethod(true); + if (getMethod != null && IsMethodOverriding(getMethod)) + { + continue; + } + + MethodInfo setMethod = property.GetSetMethod(true); + if (setMethod != null && IsMethodOverriding(setMethod)) + { + continue; + } + + if (getMethod == null) + { + ThrowInvalidDataContractException(SR.Format(SR.NoGetMethodForProperty, property.DeclaringType, property.Name)); + } + + if (setMethod == null) + { + if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: false)) + { + serializationExceptionMessage = SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property.Name); + } + } + if (getMethod.GetParameters().Length > 0) + { + ThrowInvalidDataContractException(SR.Format(SR.IndexedPropertyCannotBeSerialized, property.DeclaringType, property.Name)); + } + } + else if (member.MemberType != MemberTypes.Field) + { + ThrowInvalidDataContractException(SR.Format(SR.InvalidMember, DataContract.GetClrTypeFullName(type), member.Name)); + } + + DataMemberAttribute memberAttribute = (DataMemberAttribute)memberAttributes[0]; + if (memberAttribute.IsNameSetExplicitly) + { + if (memberAttribute.Name == null || memberAttribute.Name.Length == 0) + { + ThrowInvalidDataContractException(SR.Format(SR.InvalidDataMemberName, member.Name, DataContract.GetClrTypeFullName(type))); + } + + memberContract.Name = memberAttribute.Name; + } + else + { + memberContract.Name = member.Name; + } + + memberContract.Name = DataContract.EncodeLocalName(memberContract.Name); + memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); + memberContract.IsRequired = memberAttribute.IsRequired; + if (memberAttribute.IsRequired && IsReference) + { + ThrowInvalidDataContractException( + SR.Format(SR.IsRequiredDataMemberOnIsReferenceDataContractType, + DataContract.GetClrTypeFullName(member.DeclaringType), + member.Name, true), type); + } + memberContract.EmitDefaultValue = memberAttribute.EmitDefaultValue; + memberContract.Order = memberAttribute.Order; + CheckAndAddMember(tempMembers, memberContract, memberNamesTable); + } + } + else if (isNonAttributedType) + { + FieldInfo field = member as FieldInfo; + PropertyInfo property = member as PropertyInfo; + if ((field == null && property == null) || (field != null && field.IsInitOnly)) + { + continue; + } + + object[] memberAttributes = member.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false); + if (memberAttributes != null && memberAttributes.Length > 0) + { + if (memberAttributes.Length > 1) + { + ThrowInvalidDataContractException(SR.Format(SR.TooManyIgnoreDataMemberAttributes, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name)); + } + else + { + continue; + } + } + DataMember memberContract = new DataMember(member); + if (property != null) + { + MethodInfo getMethod = property.GetGetMethod(); + if (getMethod == null || IsMethodOverriding(getMethod) || getMethod.GetParameters().Length > 0) + { + continue; + } + + MethodInfo setMethod = property.GetSetMethod(true); + if (setMethod == null) + { + // if the collection doesn't have the 'Add' method, we will skip it, for compatibility with 4.0 + if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: true)) + { + continue; + } + } + else + { + if (!setMethod.IsPublic || IsMethodOverriding(setMethod)) + { + continue; + } + } + + //skip ExtensionData member of type ExtensionDataObject if IExtensibleDataObject is implemented in non-attributed type + if (hasExtensionData && memberContract.MemberType == Globals.TypeOfExtensionDataObject + && member.Name == Globals.ExtensionDataObjectPropertyName) + { + continue; + } + } + + memberContract.Name = DataContract.EncodeLocalName(member.Name); + memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); + CheckAndAddMember(tempMembers, memberContract, memberNamesTable); + } + else + { + FieldInfo field = member as FieldInfo; + if (field != null && !field.IsNotSerialized) + { + DataMember memberContract = new DataMember(member) + { + Name = DataContract.EncodeLocalName(member.Name) + }; + object[] optionalFields = field.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false); + if (optionalFields == null || optionalFields.Length == 0) + { + if (IsReference) + { + ThrowInvalidDataContractException( + SR.Format(SR.NonOptionalFieldMemberOnIsReferenceSerializableType, + DataContract.GetClrTypeFullName(member.DeclaringType), + member.Name, true), type); + } + memberContract.IsRequired = true; + } + memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); + CheckAndAddMember(tempMembers, memberContract, memberNamesTable); + } + } + } + if (tempMembers.Count > 1) + { + tempMembers.Sort(DataMemberComparer.Singleton); + } + + SetIfMembersHaveConflict(tempMembers); + + Thread.MemoryBarrier(); + members = tempMembers; + } + + private bool SetIfGetOnlyCollection(DataMember memberContract, bool skipIfReadOnlyContract) + { + //OK to call IsCollection here since the use of surrogated collection types is not supported in get-only scenarios + if (CollectionDataContract.IsCollection(memberContract.MemberType, false /*isConstructorRequired*/, skipIfReadOnlyContract) && !memberContract.MemberType.IsValueType) + { + memberContract.IsGetOnlyCollection = true; + return true; + } + return false; + } + + private void SetIfMembersHaveConflict(List members) + { + if (BaseContract == null) + { + return; + } + + int baseTypeIndex = 0; + List membersInHierarchy = new List(); + foreach (DataMember member in members) + { + membersInHierarchy.Add(new Member(member, StableName.Namespace, baseTypeIndex)); + } + ClassDataContract currContract = BaseContract; + while (currContract != null) + { + baseTypeIndex++; + foreach (DataMember member in currContract.Members) + { + membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex)); + } + currContract = currContract.BaseContract; + } + + IComparer comparer = DataMemberConflictComparer.Singleton; + membersInHierarchy.Sort(comparer); + + for (int i = 0; i < membersInHierarchy.Count - 1; i++) + { + int startIndex = i; + int endIndex = i; + bool hasConflictingType = false; + while (endIndex < membersInHierarchy.Count - 1 + && string.CompareOrdinal(membersInHierarchy[endIndex].member.Name, membersInHierarchy[endIndex + 1].member.Name) == 0 + && string.CompareOrdinal(membersInHierarchy[endIndex].ns, membersInHierarchy[endIndex + 1].ns) == 0) + { + membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member; + if (!hasConflictingType) + { + if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType) + { + hasConflictingType = true; + } + else + { + hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType); + } + } + endIndex++; + } + + if (hasConflictingType) + { + for (int j = startIndex; j <= endIndex; j++) + { + membersInHierarchy[j].member.HasConflictingNameAndType = true; + } + } + + i = endIndex + 1; + } + } + + private XmlQualifiedName GetStableNameAndSetHasDataContract(Type type) + { + return DataContract.GetStableName(type, out hasDataContract); + } + + private void SetIsNonAttributedType(Type type) + { + isNonAttributedType = !type.IsSerializable && !hasDataContract && IsNonAttributedTypeValidForSerialization(type); + } + + private static bool IsMethodOverriding(MethodInfo method) + { + return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0); + } + + internal void EnsureMethodsImported() + { + if (!isMethodChecked && UnderlyingType != null) + { + lock (this) + { + if (!isMethodChecked) + { + Type type = UnderlyingType; + MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + for (int i = 0; i < methods.Length; i++) + { + MethodInfo method = methods[i]; + Type prevAttributeType = null; + ParameterInfo[] parameters = method.GetParameters(); + if (HasExtensionData && IsValidExtensionDataSetMethod(method, parameters)) + { + if (method.Name == Globals.ExtensionDataSetExplicitMethod || !method.IsPublic) + { + extensionDataSetMethod = XmlFormatGeneratorStatics.ExtensionDataSetExplicitMethodInfo; + } + else + { + extensionDataSetMethod = method; + } + } + if (IsValidCallback(method, parameters, Globals.TypeOfOnSerializingAttribute, onSerializing, ref prevAttributeType)) + { + onSerializing = method; + } + + if (IsValidCallback(method, parameters, Globals.TypeOfOnSerializedAttribute, onSerialized, ref prevAttributeType)) + { + onSerialized = method; + } + + if (IsValidCallback(method, parameters, Globals.TypeOfOnDeserializingAttribute, onDeserializing, ref prevAttributeType)) + { + onDeserializing = method; + } + + if (IsValidCallback(method, parameters, Globals.TypeOfOnDeserializedAttribute, onDeserialized, ref prevAttributeType)) + { + onDeserialized = method; + } + } + Thread.MemoryBarrier(); + isMethodChecked = true; + } + } + } + } + + private bool IsValidExtensionDataSetMethod(MethodInfo method, ParameterInfo[] parameters) + { + if (method.Name == Globals.ExtensionDataSetExplicitMethod || method.Name == Globals.ExtensionDataSetMethod) + { + if (extensionDataSetMethod != null) + { + ThrowInvalidDataContractException(SR.Format(SR.DuplicateExtensionDataSetMethod, method, extensionDataSetMethod, DataContract.GetClrTypeFullName(method.DeclaringType))); + } + + if (method.ReturnType != Globals.TypeOfVoid) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.ExtensionDataSetMustReturnVoid, DataContract.GetClrTypeFullName(method.DeclaringType), method), method.DeclaringType); + } + + if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != Globals.TypeOfExtensionDataObject) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.ExtensionDataSetParameterInvalid, DataContract.GetClrTypeFullName(method.DeclaringType), method, Globals.TypeOfExtensionDataObject), method.DeclaringType); + } + + return true; + } + return false; + } + + private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType) + { + if (method.IsDefined(attributeType, false)) + { + if (currentCallback != null) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.DuplicateCallback, method, currentCallback, DataContract.GetClrTypeFullName(method.DeclaringType), attributeType), method.DeclaringType); + } + else if (prevAttributeType != null) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.DuplicateAttribute, prevAttributeType, attributeType, DataContract.GetClrTypeFullName(method.DeclaringType), method), method.DeclaringType); + } + else if (method.IsVirtual) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.CallbacksCannotBeVirtualMethods, method, DataContract.GetClrTypeFullName(method.DeclaringType), attributeType), method.DeclaringType); + } + else + { + if (method.ReturnType != Globals.TypeOfVoid) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.CallbackMustReturnVoid, DataContract.GetClrTypeFullName(method.DeclaringType), method), method.DeclaringType); + } + + if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != Globals.TypeOfStreamingContext) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.CallbackParameterInvalid, DataContract.GetClrTypeFullName(method.DeclaringType), method, Globals.TypeOfStreamingContext), method.DeclaringType); + } + + prevAttributeType = attributeType; + } + return true; + } + return false; + } + + internal ClassDataContract BaseContract + { + get => baseContract; + set + { + baseContract = value; + if (baseContract != null && IsValueType) + { + ThrowInvalidDataContractException(SR.Format(SR.ValueTypeCannotHaveBaseType, StableName.Name, StableName.Namespace, baseContract.StableName.Name, baseContract.StableName.Namespace)); + } + } + } + + internal List Members + { + get => members; + set => members = value; + } + + internal MethodInfo OnSerializing + { + get + { + EnsureMethodsImported(); + return onSerializing; + } + } + + internal MethodInfo OnSerialized + { + get + { + EnsureMethodsImported(); + return onSerialized; + } + } + + internal MethodInfo OnDeserializing + { + get + { + EnsureMethodsImported(); + return onDeserializing; + } + } + + internal MethodInfo OnDeserialized + { + get + { + EnsureMethodsImported(); + return onDeserialized; + } + } + + internal MethodInfo ExtensionDataSetMethod + { + get + { + EnsureMethodsImported(); + return extensionDataSetMethod; + } + } + + internal override DataContractDictionary KnownDataContracts + { + get + { + if (!isKnownTypeAttributeChecked && UnderlyingType != null) + { + lock (this) + { + if (!isKnownTypeAttributeChecked) + { + knownDataContracts = DataContract.ImportKnownTypeAttributes(UnderlyingType); + Thread.MemoryBarrier(); + isKnownTypeAttributeChecked = true; + } + } + } + return knownDataContracts; + } + set => knownDataContracts = value; + } + + internal string SerializationExceptionMessage => serializationExceptionMessage; + + internal string DeserializationExceptionMessage + { + get + { + if (serializationExceptionMessage == null) + { + return null; + } + else + { + return SR.Format(SR.ReadOnlyClassDeserialization, serializationExceptionMessage); + } + } + } + + internal override bool IsISerializable + { + get => isISerializable; + set => isISerializable = value; + } + + internal bool HasDataContract => hasDataContract; + + internal bool HasExtensionData => hasExtensionData; + + internal bool IsNonAttributedType => isNonAttributedType; + + internal ConstructorInfo GetISerializableConstructor() + { + if (!IsISerializable) + { + return null; + } + + ConstructorInfo ctor = UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, SerInfoCtorArgs, null); + if (ctor == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + return ctor; + } + + internal ConstructorInfo GetNonAttributedTypeConstructor() + { + if (!IsNonAttributedType) + { + return null; + } + + Type type = UnderlyingType; + + if (type.IsValueType) + { + return null; + } + + ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + if (ctor == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); + } + + return ctor; + } + + internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate + { + get => xmlFormatWriterDelegate; + set => xmlFormatWriterDelegate = value; + } + + internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate + { + get => xmlFormatReaderDelegate; + set => xmlFormatReaderDelegate = value; + } + + public XmlDictionaryString[] ChildElementNamespaces + { + get => childElementNamespaces; + set => childElementNamespaces = value; + } + + private static Type[] serInfoCtorArgs; + + private static Type[] SerInfoCtorArgs + { + get + { + if (serInfoCtorArgs == null) + { + serInfoCtorArgs = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; + } + + return serInfoCtorArgs; + } + } + + internal struct Member + { + internal Member(DataMember member, string ns, int baseTypeIndex) + { + this.member = member; + this.ns = ns; + this.baseTypeIndex = baseTypeIndex; + } + internal DataMember member; + internal string ns; + internal int baseTypeIndex; + } + + internal class DataMemberConflictComparer : IComparer + { + public int Compare(Member x, Member y) + { + int nsCompare = string.CompareOrdinal(x.ns, y.ns); + if (nsCompare != 0) + { + return nsCompare; + } + + int nameCompare = string.CompareOrdinal(x.member.Name, y.member.Name); + if (nameCompare != 0) + { + return nameCompare; + } + + return x.baseTypeIndex - y.baseTypeIndex; + } + + internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer(); + } + + } + + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + Type type = UnderlyingType; + if (!type.IsGenericType || !type.ContainsGenericParameters) + { + return this; + } + + lock (this) + { + if (boundContracts.TryGetValue(this, out DataContract boundContract)) + { + return boundContract; + } + + ClassDataContract boundClassContract = new ClassDataContract(); + boundContracts.Add(this, boundClassContract); + XmlQualifiedName stableName; + object[] genericParams; + if (type.IsGenericTypeDefinition) + { + stableName = StableName; + genericParams = paramContracts; + } + else + { + //partial Generic: Construct stable name from its open generic type definition + stableName = DataContract.GetStableName(type.GetGenericTypeDefinition()); + Type[] paramTypes = type.GetGenericArguments(); + genericParams = new object[paramTypes.Length]; + for (int i = 0; i < paramTypes.Length; i++) + { + Type paramType = paramTypes[i]; + if (paramType.IsGenericParameter) + { + genericParams[i] = paramContracts[paramType.GenericParameterPosition]; + } + else + { + genericParams[i] = paramType; + } + } + } + boundClassContract.StableName = CreateQualifiedName( + DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), + new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), genericParams)), + stableName.Namespace); + if (BaseContract != null) + { + boundClassContract.BaseContract = (ClassDataContract)BaseContract.BindGenericParameters(paramContracts, boundContracts); + } + + boundClassContract.IsISerializable = IsISerializable; + boundClassContract.IsValueType = IsValueType; + boundClassContract.IsReference = IsReference; + if (Members != null) + { + boundClassContract.Members = new List(Members.Count); + foreach (DataMember member in Members) + { + boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts)); + } + } + return boundClassContract; + } + } + + internal override bool Equals(object other, Dictionary checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + { + return true; + } + + if (base.Equals(other, checkedContracts)) + { + ClassDataContract dataContract = other as ClassDataContract; + if (dataContract != null) + { + if (IsISerializable) + { + if (!dataContract.IsISerializable) + { + return false; + } + } + else + { + if (dataContract.IsISerializable) + { + return false; + } + + if (Members == null) + { + if (dataContract.Members != null) + { + // check that all the datamembers in dataContract.Members are optional + if (!IsEveryDataMemberOptional(dataContract.Members)) + { + return false; + } + } + } + else if (dataContract.Members == null) + { + // check that all the datamembers in Members are optional + if (!IsEveryDataMemberOptional(Members)) + { + return false; + } + } + else + { + Dictionary membersDictionary = new Dictionary(Members.Count); + List dataContractMembersList = new List(); + for (int i = 0; i < Members.Count; i++) + { + membersDictionary.Add(Members[i].Name, Members[i]); + } + + for (int i = 0; i < dataContract.Members.Count; i++) + { + // check that all datamembers common to both datacontracts match + if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out DataMember dataMember)) + { + if (dataMember.Equals(dataContract.Members[i], checkedContracts)) + { + membersDictionary.Remove(dataMember.Name); + } + else + { + return false; + } + } + // otherwise save the non-matching datamembers for later verification + else + { + dataContractMembersList.Add(dataContract.Members[i]); + } + } + + // check that datamembers left over from either datacontract are optional + if (!IsEveryDataMemberOptional(membersDictionary.Values)) + { + return false; + } + + if (!IsEveryDataMemberOptional(dataContractMembersList)) + { + return false; + } + } + } + + if (BaseContract == null) + { + return (dataContract.BaseContract == null); + } + else if (dataContract.BaseContract == null) + { + return false; + } + else + { + return BaseContract.Equals(dataContract.BaseContract, checkedContracts); + } + } + } + return false; + } + + private bool IsEveryDataMemberOptional(IEnumerable dataMembers) + { + foreach (DataMember dataMember in dataMembers) + { + if (dataMember.IsRequired) + { + return false; + } + } + return true; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + internal class DataMemberComparer : IComparer + { + public int Compare(DataMember x, DataMember y) + { + int orderCompare = x.Order - y.Order; + if (orderCompare != 0) + { + return orderCompare; + } + + return string.CompareOrdinal(x.Name, y.Name); + } + + internal static DataMemberComparer Singleton = new DataMemberComparer(); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataNode.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataNode.cs new file mode 100644 index 0000000..6e2c45f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ClassDataNode.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + internal class ClassDataNode : DataNode + { + private IList _members; + + internal ClassDataNode() + { + dataType = Globals.TypeOfClassDataNode; + } + + internal IList Members + { + get => _members; + set => _members = value; + } + + public override void Clear() + { + base.Clear(); + _members = null; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/CodeGenerator.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/CodeGenerator.cs new file mode 100644 index 0000000..929edfb --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/CodeGenerator.cs @@ -0,0 +1,2360 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Reflection; +using System.Reflection.Emit; + +namespace Compat.Runtime.Serialization +{ + internal class CodeGenerator + { + private static MethodInfo getTypeFromHandle; + + private static MethodInfo GetTypeFromHandle + { + get + { + if (getTypeFromHandle == null) + { + getTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)); + } + + return getTypeFromHandle; + } + } + + private static MethodInfo stringFormat; + + private static MethodInfo StringFormat + { + get + { + if (stringFormat == null) + { + stringFormat = typeof(string).GetMethod(nameof(string.Format), new Type[] { typeof(string), typeof(object[]) }); + } + + return stringFormat; + } + } + + private static MethodInfo stringConcat2; + + private static MethodInfo StringConcat2 + { + get + { + if (stringConcat2 == null) + { + stringConcat2 = typeof(string).GetMethod(nameof(string.Concat), new Type[] { typeof(string), typeof(string) }); + } + + return stringConcat2; + } + } + + private static MethodInfo stringConcat3; + + private static MethodInfo StringConcat3 + { + get + { + if (stringConcat3 == null) + { + stringConcat3 = typeof(string).GetMethod(nameof(string.Concat), new Type[] { typeof(string), typeof(string), typeof(string) }); + } + + return stringConcat3; + } + } + + private static MethodInfo objectToString; + + private static MethodInfo ObjectToString + { + get + { + if (objectToString == null) + { + objectToString = typeof(object).GetMethod(nameof(object.ToString), new Type[0]); + } + + return objectToString; + } + } + + private static MethodInfo objectEquals; + + private static MethodInfo ObjectEquals + { + get + { + if (objectEquals == null) + { + objectEquals = Globals.TypeOfObject.GetMethod("Equals", BindingFlags.Public | BindingFlags.Static); + } + + return objectEquals; + } + } + + private static MethodInfo arraySetValue; + + private static MethodInfo ArraySetValue + { + get + { + if (arraySetValue == null) + { + arraySetValue = typeof(Array).GetMethod("SetValue", new Type[] { typeof(object), typeof(int) }); + } + + return arraySetValue; + } + } + + private Type delegateType; + + private static Module serializationModule; + + private static Module SerializationModule + { + get + { + if (serializationModule == null) + { + serializationModule = typeof(CodeGenerator).Module; // could to be replaced by different dll that has SkipVerification set to false + } + return serializationModule; + } + } + + private DynamicMethod dynamicMethod; + private ILGenerator ilGen; + private ArrayList argList; + private Stack blockStack; + private Label methodEndLabel; + private LocalBuilder stringFormatArray; + private Hashtable localNames; + private int lineNo = 1; + + private enum CodeGenTrace { None, Save, Tron }; + + private CodeGenTrace codeGenTrace; + + internal CodeGenerator() + { + SourceSwitch codeGenSwitch = SerializationTrace.CodeGenerationSwitch; + if ((codeGenSwitch.Level & SourceLevels.Verbose) == SourceLevels.Verbose) + { + codeGenTrace = CodeGenTrace.Tron; + } + else if ((codeGenSwitch.Level & SourceLevels.Information) == SourceLevels.Information) + { + codeGenTrace = CodeGenTrace.Save; + } + else + { + codeGenTrace = CodeGenTrace.None; + } + } + + internal void BeginMethod(DynamicMethod dynamicMethod, Type delegateType, string methodName, Type[] argTypes, bool allowPrivateMemberAccess) + { + this.dynamicMethod = dynamicMethod; + ilGen = this.dynamicMethod.GetILGenerator(); + this.delegateType = delegateType; + + InitILGeneration(methodName, argTypes); + } + + internal void BeginMethod(string methodName, Type delegateType, bool allowPrivateMemberAccess) + { + MethodInfo signature = delegateType.GetMethod("Invoke"); + ParameterInfo[] parameters = signature.GetParameters(); + Type[] paramTypes = new Type[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + paramTypes[i] = parameters[i].ParameterType; + } + + BeginMethod(signature.ReturnType, methodName, paramTypes, allowPrivateMemberAccess); + this.delegateType = delegateType; + } + + private void BeginMethod(Type returnType, string methodName, Type[] argTypes, bool allowPrivateMemberAccess) + { + dynamicMethod = new DynamicMethod(methodName, returnType, argTypes, SerializationModule, allowPrivateMemberAccess); + ilGen = dynamicMethod.GetILGenerator(); + InitILGeneration(methodName, argTypes); + } + + private void InitILGeneration(string methodName, Type[] argTypes) + { + methodEndLabel = ilGen.DefineLabel(); + blockStack = new Stack(); + argList = new ArrayList(); + for (int i = 0; i < argTypes.Length; i++) + { + argList.Add(new ArgBuilder(i, argTypes[i])); + } + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceLabel("Begin method " + methodName + " {"); + } + } + + internal Delegate EndMethod() + { + MarkLabel(methodEndLabel); + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceLabel("} End method"); + } + + Ret(); + + Delegate retVal = null; + retVal = dynamicMethod.CreateDelegate(delegateType); + dynamicMethod = null; + delegateType = null; + + ilGen = null; + blockStack = null; + argList = null; + return retVal; + } + + internal MethodInfo CurrentMethod => dynamicMethod; + + internal ArgBuilder GetArg(int index) + { + return (ArgBuilder)argList[index]; + } + + internal Type GetVariableType(object var) + { + if (var is ArgBuilder) + { + return ((ArgBuilder)var).ArgType; + } + else if (var is LocalBuilder) + { + return ((LocalBuilder)var).LocalType; + } + else + { + return var.GetType(); + } + } + + internal LocalBuilder DeclareLocal(Type type, string name, object initialValue) + { + LocalBuilder local = DeclareLocal(type, name); + Load(initialValue); + Store(local); + return local; + } + + internal LocalBuilder DeclareLocal(Type type, string name) + { + return DeclareLocal(type, name, false); + } + + internal LocalBuilder DeclareLocal(Type type, string name, bool isPinned) + { + LocalBuilder local = ilGen.DeclareLocal(type, isPinned); + if (codeGenTrace != CodeGenTrace.None) + { + LocalNames[local] = name; + EmitSourceComment("Declare local '" + name + "' of type " + type); + } + return local; + } + + internal void Set(LocalBuilder local, object value) + { + Load(value); + Store(local); + } + + internal object For(LocalBuilder local, object start, object end) + { + ForState forState = new ForState(local, DefineLabel(), DefineLabel(), end); + if (forState.Index != null) + { + Load(start); + Stloc(forState.Index); + Br(forState.TestLabel); + } + MarkLabel(forState.BeginLabel); + blockStack.Push(forState); + return forState; + } + + internal void EndFor() + { + object stackTop = blockStack.Pop(); + ForState forState = stackTop as ForState; + if (forState == null) + { + ThrowMismatchException(stackTop); + } + + if (forState.Index != null) + { + Ldloc(forState.Index); + Ldc(1); + Add(); + Stloc(forState.Index); + MarkLabel(forState.TestLabel); + Ldloc(forState.Index); + Load(forState.End); + if (GetVariableType(forState.End).IsArray) + { + Ldlen(); + } + + Blt(forState.BeginLabel); + } + else + { + Br(forState.BeginLabel); + } + + if (forState.RequiresEndLabel) + { + MarkLabel(forState.EndLabel); + } + } + + internal void Break(object forState) + { + InternalBreakFor(forState, OpCodes.Br); + } + + internal void IfTrueBreak(object forState) + { + InternalBreakFor(forState, OpCodes.Brtrue); + } + + internal void IfFalseBreak(object forState) + { + InternalBreakFor(forState, OpCodes.Brfalse); + } + + internal void InternalBreakFor(object userForState, OpCode branchInstruction) + { + foreach (object block in blockStack) + { + ForState forState = block as ForState; + if (forState != null && (object)forState == userForState) + { + if (!forState.RequiresEndLabel) + { + forState.EndLabel = DefineLabel(); + forState.RequiresEndLabel = true; + } + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction(branchInstruction + " " + forState.EndLabel.GetHashCode()); + } + + ilGen.Emit(branchInstruction, forState.EndLabel); + break; + } + } + } + + internal void ForEach(LocalBuilder local, Type elementType, Type enumeratorType, + LocalBuilder enumerator, MethodInfo getCurrentMethod) + { + ForState forState = new ForState(local, DefineLabel(), DefineLabel(), enumerator); + + Br(forState.TestLabel); + MarkLabel(forState.BeginLabel); + + Call(enumerator, getCurrentMethod); + + ConvertValue(elementType, GetVariableType(local)); + Stloc(local); + blockStack.Push(forState); + } + + internal void EndForEach(MethodInfo moveNextMethod) + { + object stackTop = blockStack.Pop(); + ForState forState = stackTop as ForState; + if (forState == null) + { + ThrowMismatchException(stackTop); + } + + MarkLabel(forState.TestLabel); + + object enumerator = forState.End; + Call(enumerator, moveNextMethod); + + + Brtrue(forState.BeginLabel); + if (forState.RequiresEndLabel) + { + MarkLabel(forState.EndLabel); + } + } + + internal void IfNotDefaultValue(object value) + { + Type type = GetVariableType(value); + TypeCode typeCode = Type.GetTypeCode(type); + if ((typeCode == TypeCode.Object && type.IsValueType) || + typeCode == TypeCode.DateTime || typeCode == TypeCode.Decimal) + { + LoadDefaultValue(type); + ConvertValue(type, Globals.TypeOfObject); + Load(value); + ConvertValue(type, Globals.TypeOfObject); + Call(ObjectEquals); + IfNot(); + } + else + { + LoadDefaultValue(type); + Load(value); + If(Cmp.NotEqualTo); + } + } + + internal void If() + { + InternalIf(false); + } + + internal void IfNot() + { + InternalIf(true); + } + + private OpCode GetBranchCode(Cmp cmp) + { + switch (cmp) + { + case Cmp.LessThan: + return OpCodes.Bge; + case Cmp.EqualTo: + return OpCodes.Bne_Un; + case Cmp.LessThanOrEqualTo: + return OpCodes.Bgt; + case Cmp.GreaterThan: + return OpCodes.Ble; + case Cmp.NotEqualTo: + return OpCodes.Beq; + default: + Fx.Assert(cmp == Cmp.GreaterThanOrEqualTo, "Unexpected cmp"); + return OpCodes.Blt; + } + } + + private Cmp GetCmpInverse(Cmp cmp) + { + switch (cmp) + { + case Cmp.LessThan: + return Cmp.GreaterThanOrEqualTo; + case Cmp.EqualTo: + return Cmp.NotEqualTo; + case Cmp.LessThanOrEqualTo: + return Cmp.GreaterThan; + case Cmp.GreaterThan: + return Cmp.LessThanOrEqualTo; + case Cmp.NotEqualTo: + return Cmp.EqualTo; + default: + Fx.Assert(cmp == Cmp.GreaterThanOrEqualTo, "Unexpected cmp"); + return Cmp.LessThan; + } + } + + internal void If(Cmp cmpOp) + { + IfState ifState = new IfState + { + EndIf = DefineLabel(), + ElseBegin = DefineLabel() + }; + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Branch if " + GetCmpInverse(cmpOp).ToString() + " to " + ifState.ElseBegin.GetHashCode().ToString(NumberFormatInfo.InvariantInfo)); + } + + ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin); + blockStack.Push(ifState); + } + + + internal void If(object value1, Cmp cmpOp, object value2) + { + Load(value1); + Load(value2); + If(cmpOp); + } + internal void Else() + { + IfState ifState = PopIfState(); + Br(ifState.EndIf); + MarkLabel(ifState.ElseBegin); + + ifState.ElseBegin = ifState.EndIf; + blockStack.Push(ifState); + } + + internal void ElseIf(object value1, Cmp cmpOp, object value2) + { + IfState ifState = (IfState)blockStack.Pop(); + Br(ifState.EndIf); + MarkLabel(ifState.ElseBegin); + + Load(value1); + Load(value2); + ifState.ElseBegin = DefineLabel(); + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Branch if " + GetCmpInverse(cmpOp).ToString() + " to " + ifState.ElseBegin.GetHashCode().ToString(NumberFormatInfo.InvariantInfo)); + } + + ilGen.Emit(GetBranchCode(cmpOp), ifState.ElseBegin); + blockStack.Push(ifState); + } + + + internal void EndIf() + { + IfState ifState = PopIfState(); + if (!ifState.ElseBegin.Equals(ifState.EndIf)) + { + MarkLabel(ifState.ElseBegin); + } + + MarkLabel(ifState.EndIf); + } + + internal void VerifyParameterCount(MethodInfo methodInfo, int expectedCount) + { + if (methodInfo.GetParameters().Length != expectedCount) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ParameterCountMismatch, methodInfo.Name, methodInfo.GetParameters().Length, expectedCount))); + } + } + + internal void Call(object thisObj, MethodInfo methodInfo) + { + VerifyParameterCount(methodInfo, 0); + LoadThis(thisObj, methodInfo); + Call(methodInfo); + } + + internal void Call(object thisObj, MethodInfo methodInfo, object param1) + { + VerifyParameterCount(methodInfo, 1); + LoadThis(thisObj, methodInfo); + LoadParam(param1, 1, methodInfo); + Call(methodInfo); + } + + internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2) + { + VerifyParameterCount(methodInfo, 2); + LoadThis(thisObj, methodInfo); + LoadParam(param1, 1, methodInfo); + LoadParam(param2, 2, methodInfo); + Call(methodInfo); + } + + internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3) + { + VerifyParameterCount(methodInfo, 3); + LoadThis(thisObj, methodInfo); + LoadParam(param1, 1, methodInfo); + LoadParam(param2, 2, methodInfo); + LoadParam(param3, 3, methodInfo); + Call(methodInfo); + } + + internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3, object param4) + { + VerifyParameterCount(methodInfo, 4); + LoadThis(thisObj, methodInfo); + LoadParam(param1, 1, methodInfo); + LoadParam(param2, 2, methodInfo); + LoadParam(param3, 3, methodInfo); + LoadParam(param4, 4, methodInfo); + Call(methodInfo); + } + + internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3, object param4, object param5) + { + VerifyParameterCount(methodInfo, 5); + LoadThis(thisObj, methodInfo); + LoadParam(param1, 1, methodInfo); + LoadParam(param2, 2, methodInfo); + LoadParam(param3, 3, methodInfo); + LoadParam(param4, 4, methodInfo); + LoadParam(param5, 5, methodInfo); + Call(methodInfo); + } + + internal void Call(object thisObj, MethodInfo methodInfo, object param1, object param2, object param3, object param4, object param5, object param6) + { + VerifyParameterCount(methodInfo, 6); + LoadThis(thisObj, methodInfo); + LoadParam(param1, 1, methodInfo); + LoadParam(param2, 2, methodInfo); + LoadParam(param3, 3, methodInfo); + LoadParam(param4, 4, methodInfo); + LoadParam(param5, 5, methodInfo); + LoadParam(param6, 6, methodInfo); + Call(methodInfo); + } + + internal void Call(MethodInfo methodInfo) + { + if (methodInfo.IsVirtual && !methodInfo.DeclaringType.IsValueType) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Callvirt " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); + } + + ilGen.Emit(OpCodes.Callvirt, methodInfo); + } + else if (methodInfo.IsStatic) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Static Call " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); + } + + ilGen.Emit(OpCodes.Call, methodInfo); + } + else + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Call " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); + } + + ilGen.Emit(OpCodes.Call, methodInfo); + } + } + + internal void Call(ConstructorInfo ctor) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Call " + ctor.ToString() + " on type " + ctor.DeclaringType.ToString()); + } + + ilGen.Emit(OpCodes.Call, ctor); + } + + internal void New(ConstructorInfo constructorInfo) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Newobj " + constructorInfo.ToString() + " on type " + constructorInfo.DeclaringType.ToString()); + } + + ilGen.Emit(OpCodes.Newobj, constructorInfo); + } + + internal void New(ConstructorInfo constructorInfo, object param1) + { + LoadParam(param1, 1, constructorInfo); + New(constructorInfo); + } + + internal void InitObj(Type valueType) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Initobj " + valueType); + } + + ilGen.Emit(OpCodes.Initobj, valueType); + } + + internal void NewArray(Type elementType, object len) + { + Load(len); + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Newarr " + elementType); + } + + ilGen.Emit(OpCodes.Newarr, elementType); + } + + internal void IgnoreReturnValue() + { + Pop(); + } + + internal void LoadArrayElement(object obj, object arrayIndex) + { + Type objType = GetVariableType(obj).GetElementType(); + Load(obj); + Load(arrayIndex); + if (IsStruct(objType)) + { + Ldelema(objType); + Ldobj(objType); + } + else + { + Ldelem(objType); + } + } + + internal void StoreArrayElement(object obj, object arrayIndex, object value) + { + Type arrayType = GetVariableType(obj); + if (arrayType == Globals.TypeOfArray) + { + Call(obj, ArraySetValue, value, arrayIndex); + } + else + { + Type objType = arrayType.GetElementType(); + Load(obj); + Load(arrayIndex); + if (IsStruct(objType)) + { + Ldelema(objType); + } + + Load(value); + ConvertValue(GetVariableType(value), objType); + if (IsStruct(objType)) + { + Stobj(objType); + } + else + { + Stelem(objType); + } + } + } + + private static bool IsStruct(Type objType) + { + return objType.IsValueType && !objType.IsPrimitive; + } + + internal Type LoadMember(MemberInfo memberInfo) + { + Type memberType = null; + if (memberInfo.MemberType == MemberTypes.Field) + { + FieldInfo fieldInfo = (FieldInfo)memberInfo; + memberType = fieldInfo.FieldType; + if (fieldInfo.IsStatic) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldsfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); + } + + ilGen.Emit(OpCodes.Ldsfld, fieldInfo); + } + else + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); + } + + ilGen.Emit(OpCodes.Ldfld, fieldInfo); + } + } + else if (memberInfo.MemberType == MemberTypes.Property) + { + PropertyInfo property = memberInfo as PropertyInfo; + memberType = property.PropertyType; + if (property != null) + { + MethodInfo getMethod = property.GetGetMethod(true); + if (getMethod == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoGetMethodForProperty, property.DeclaringType, property))); + } + + Call(getMethod); + } + } + else if (memberInfo.MemberType == MemberTypes.Method) + { + MethodInfo method = (MethodInfo)memberInfo; + memberType = method.ReturnType; + Call(method); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, memberInfo.MemberType, memberInfo.DeclaringType, memberInfo.Name))); + } + + EmitStackTop(memberType); + return memberType; + } + + internal void StoreMember(MemberInfo memberInfo) + { + if (memberInfo.MemberType == MemberTypes.Field) + { + FieldInfo fieldInfo = (FieldInfo)memberInfo; + if (fieldInfo.IsStatic) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Stsfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); + } + + ilGen.Emit(OpCodes.Stsfld, fieldInfo); + } + else + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Stfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); + } + + ilGen.Emit(OpCodes.Stfld, fieldInfo); + } + } + else if (memberInfo.MemberType == MemberTypes.Property) + { + PropertyInfo property = memberInfo as PropertyInfo; + if (property != null) + { + MethodInfo setMethod = property.GetSetMethod(true); + if (setMethod == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property))); + } + + Call(setMethod); + } + } + else if (memberInfo.MemberType == MemberTypes.Method) + { + Call((MethodInfo)memberInfo); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, memberInfo.MemberType))); + } + } + + internal void LoadDefaultValue(Type type) + { + if (type.IsValueType) + { + switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + Ldc(false); + break; + case TypeCode.Char: + case TypeCode.SByte: + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + Ldc(0); + break; + case TypeCode.Int64: + case TypeCode.UInt64: + Ldc(0L); + break; + case TypeCode.Single: + Ldc(0.0F); + break; + case TypeCode.Double: + Ldc(0.0); + break; + case TypeCode.Decimal: + case TypeCode.DateTime: + default: + LocalBuilder zero = DeclareLocal(type, "zero"); + LoadAddress(zero); + InitObj(type); + Load(zero); + break; + } + } + else + { + Load(null); + } + } + + internal void Load(object obj) + { + if (obj == null) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldnull"); + } + + ilGen.Emit(OpCodes.Ldnull); + } + else if (obj is ArgBuilder) + { + Ldarg((ArgBuilder)obj); + } + else if (obj is LocalBuilder) + { + Ldloc((LocalBuilder)obj); + } + else + { + Ldc(obj); + } + } + + internal void Store(object var) + { + if (var is ArgBuilder) + { + Starg((ArgBuilder)var); + } + else if (var is LocalBuilder) + { + Stloc((LocalBuilder)var); + } + else + { + Fx.Assert("Data can only be stored into ArgBuilder or LocalBuilder."); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CanOnlyStoreIntoArgOrLocGot0, DataContract.GetClrTypeFullName(var.GetType())))); + } + } + + internal void Dec(object var) + { + Load(var); + Load(1); + Subtract(); + Store(var); + } + + internal void Inc(object var) + { + Load(var); + Load(1); + Add(); + Store(var); + } + + internal void LoadAddress(object obj) + { + if (obj is ArgBuilder) + { + LdargAddress((ArgBuilder)obj); + } + else if (obj is LocalBuilder) + { + LdlocAddress((LocalBuilder)obj); + } + else + { + Load(obj); + } + } + + + internal void ConvertAddress(Type source, Type target) + { + InternalConvert(source, target, true); + } + + internal void ConvertValue(Type source, Type target) + { + InternalConvert(source, target, false); + } + + + internal void Castclass(Type target) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Castclass " + target); + } + + ilGen.Emit(OpCodes.Castclass, target); + } + + internal void Box(Type type) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Box " + type); + } + + ilGen.Emit(OpCodes.Box, type); + } + + internal void Unbox(Type type) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Unbox " + type); + } + + ilGen.Emit(OpCodes.Unbox, type); + } + + private OpCode GetLdindOpCode(TypeCode typeCode) + { + switch (typeCode) + { + case TypeCode.Boolean: + return OpCodes.Ldind_I1; // TypeCode.Boolean: + case TypeCode.Char: + return OpCodes.Ldind_I2; // TypeCode.Char: + case TypeCode.SByte: + return OpCodes.Ldind_I1; // TypeCode.SByte: + case TypeCode.Byte: + return OpCodes.Ldind_U1; // TypeCode.Byte: + case TypeCode.Int16: + return OpCodes.Ldind_I2; // TypeCode.Int16: + case TypeCode.UInt16: + return OpCodes.Ldind_U2; // TypeCode.UInt16: + case TypeCode.Int32: + return OpCodes.Ldind_I4; // TypeCode.Int32: + case TypeCode.UInt32: + return OpCodes.Ldind_U4; // TypeCode.UInt32: + case TypeCode.Int64: + return OpCodes.Ldind_I8; // TypeCode.Int64: + case TypeCode.UInt64: + return OpCodes.Ldind_I8; // TypeCode.UInt64: + case TypeCode.Single: + return OpCodes.Ldind_R4; // TypeCode.Single: + case TypeCode.Double: + return OpCodes.Ldind_R8; // TypeCode.Double: + case TypeCode.String: + return OpCodes.Ldind_Ref; // TypeCode.String: + default: + return OpCodes.Nop; + } + // + } + + internal void Ldobj(Type type) + { + OpCode opCode = GetLdindOpCode(Type.GetTypeCode(type)); + if (!opCode.Equals(OpCodes.Nop)) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction(opCode.ToString()); + } + + ilGen.Emit(opCode); + } + else + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldobj " + type); + } + + ilGen.Emit(OpCodes.Ldobj, type); + } + } + + internal void Stobj(Type type) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Stobj " + type); + } + + ilGen.Emit(OpCodes.Stobj, type); + } + + + internal void Ceq() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ceq"); + } + + ilGen.Emit(OpCodes.Ceq); + } + + internal void Bgt(Label label) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Bgt " + label.GetHashCode()); + } + + ilGen.Emit(OpCodes.Bgt, label); + } + + internal void Ble(Label label) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ble " + label.GetHashCode()); + } + + ilGen.Emit(OpCodes.Ble, label); + } + + internal void Throw() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Throw"); + } + + ilGen.Emit(OpCodes.Throw); + } + + internal void Ldtoken(Type t) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldtoken " + t); + } + + ilGen.Emit(OpCodes.Ldtoken, t); + } + + internal void Ldc(object o) + { + Type valueType = o.GetType(); + if (o is Type) + { + Ldtoken((Type)o); + Call(GetTypeFromHandle); + } + else if (valueType.IsEnum) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceComment("Ldc " + o.GetType() + "." + o); + } + + Ldc(((IConvertible)o).ToType(Enum.GetUnderlyingType(valueType), null)); + } + else + { + switch (Type.GetTypeCode(valueType)) + { + case TypeCode.Boolean: + Ldc((bool)o); + break; + case TypeCode.Char: + Fx.Assert("Char is not a valid schema primitive and should be treated as int in DataContract"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.CharIsInvalidPrimitive)); + case TypeCode.SByte: + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.UInt16: + Ldc(((IConvertible)o).ToInt32(CultureInfo.InvariantCulture)); + break; + case TypeCode.Int32: + Ldc((int)o); + break; + case TypeCode.UInt32: + Ldc((int)(uint)o); + break; + case TypeCode.UInt64: + Ldc((long)(ulong)o); + break; + case TypeCode.Int64: + Ldc((long)o); + break; + case TypeCode.Single: + Ldc((float)o); + break; + case TypeCode.Double: + Ldc((double)o); + break; + case TypeCode.String: + Ldstr((string)o); + break; + case TypeCode.Object: + case TypeCode.Decimal: + case TypeCode.DateTime: + case TypeCode.Empty: + case TypeCode.DBNull: + default: + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType)))); + } + } + } + + internal void Ldc(bool boolVar) + { + if (boolVar) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldc.i4 1"); + } + + ilGen.Emit(OpCodes.Ldc_I4_1); + } + else + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldc.i4 0"); + } + + ilGen.Emit(OpCodes.Ldc_I4_0); + } + } + + internal void Ldc(int intVar) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldc.i4 " + intVar); + } + + switch (intVar) + { + case -1: + ilGen.Emit(OpCodes.Ldc_I4_M1); + break; + case 0: + ilGen.Emit(OpCodes.Ldc_I4_0); + break; + case 1: + ilGen.Emit(OpCodes.Ldc_I4_1); + break; + case 2: + ilGen.Emit(OpCodes.Ldc_I4_2); + break; + case 3: + ilGen.Emit(OpCodes.Ldc_I4_3); + break; + case 4: + ilGen.Emit(OpCodes.Ldc_I4_4); + break; + case 5: + ilGen.Emit(OpCodes.Ldc_I4_5); + break; + case 6: + ilGen.Emit(OpCodes.Ldc_I4_6); + break; + case 7: + ilGen.Emit(OpCodes.Ldc_I4_7); + break; + case 8: + ilGen.Emit(OpCodes.Ldc_I4_8); + break; + default: + ilGen.Emit(OpCodes.Ldc_I4, intVar); + break; + } + } + + internal void Ldc(long l) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldc.i8 " + l); + } + + ilGen.Emit(OpCodes.Ldc_I8, l); + } + + internal void Ldc(float f) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldc.r4 " + f); + } + + ilGen.Emit(OpCodes.Ldc_R4, f); + } + + internal void Ldc(double d) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldc.r8 " + d); + } + + ilGen.Emit(OpCodes.Ldc_R8, d); + } + + internal void Ldstr(string strVar) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldstr " + strVar); + } + + ilGen.Emit(OpCodes.Ldstr, strVar); + } + + internal void LdlocAddress(LocalBuilder localBuilder) + { + if (localBuilder.LocalType.IsValueType) + { + Ldloca(localBuilder); + } + else + { + Ldloc(localBuilder); + } + } + + internal void Ldloc(LocalBuilder localBuilder) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldloc " + LocalNames[localBuilder]); + } + + ilGen.Emit(OpCodes.Ldloc, localBuilder); + EmitStackTop(localBuilder.LocalType); + } + + internal void Stloc(LocalBuilder local) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Stloc " + LocalNames[local]); + } + + EmitStackTop(local.LocalType); + ilGen.Emit(OpCodes.Stloc, local); + } + + internal void Ldloc(int slot) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldloc " + slot); + } + + switch (slot) + { + case 0: + ilGen.Emit(OpCodes.Ldloc_0); + break; + case 1: + ilGen.Emit(OpCodes.Ldloc_1); + break; + case 2: + ilGen.Emit(OpCodes.Ldloc_2); + break; + case 3: + ilGen.Emit(OpCodes.Ldloc_3); + break; + default: + if (slot <= 255) + { + ilGen.Emit(OpCodes.Ldloc_S, slot); + } + else + { + ilGen.Emit(OpCodes.Ldloc, slot); + } + + break; + } + } + + internal void Stloc(int slot) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Stloc " + slot); + } + + switch (slot) + { + case 0: + ilGen.Emit(OpCodes.Stloc_0); + break; + case 1: + ilGen.Emit(OpCodes.Stloc_1); + break; + case 2: + ilGen.Emit(OpCodes.Stloc_2); + break; + case 3: + ilGen.Emit(OpCodes.Stloc_3); + break; + default: + if (slot <= 255) + { + ilGen.Emit(OpCodes.Stloc_S, slot); + } + else + { + ilGen.Emit(OpCodes.Stloc, slot); + } + + break; + } + } + + internal void Ldloca(LocalBuilder localBuilder) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldloca " + LocalNames[localBuilder]); + } + + ilGen.Emit(OpCodes.Ldloca, localBuilder); + EmitStackTop(localBuilder.LocalType); + } + + internal void Ldloca(int slot) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldloca " + slot); + } + + if (slot <= 255) + { + ilGen.Emit(OpCodes.Ldloca_S, slot); + } + else + { + ilGen.Emit(OpCodes.Ldloca, slot); + } + } + + internal void LdargAddress(ArgBuilder argBuilder) + { + if (argBuilder.ArgType.IsValueType) + { + Ldarga(argBuilder); + } + else + { + Ldarg(argBuilder); + } + } + + internal void Ldarg(ArgBuilder arg) + { + Ldarg(arg.Index); + } + + internal void Starg(ArgBuilder arg) + { + Starg(arg.Index); + } + + internal void Ldarg(int slot) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldarg " + slot); + } + + switch (slot) + { + case 0: + ilGen.Emit(OpCodes.Ldarg_0); + break; + case 1: + ilGen.Emit(OpCodes.Ldarg_1); + break; + case 2: + ilGen.Emit(OpCodes.Ldarg_2); + break; + case 3: + ilGen.Emit(OpCodes.Ldarg_3); + break; + default: + if (slot <= 255) + { + ilGen.Emit(OpCodes.Ldarg_S, slot); + } + else + { + ilGen.Emit(OpCodes.Ldarg, slot); + } + + break; + } + } + + internal void Starg(int slot) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Starg " + slot); + } + + if (slot <= 255) + { + ilGen.Emit(OpCodes.Starg_S, slot); + } + else + { + ilGen.Emit(OpCodes.Starg, slot); + } + } + + internal void Ldarga(ArgBuilder argBuilder) + { + Ldarga(argBuilder.Index); + } + + internal void Ldarga(int slot) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldarga " + slot); + } + + if (slot <= 255) + { + ilGen.Emit(OpCodes.Ldarga_S, slot); + } + else + { + ilGen.Emit(OpCodes.Ldarga, slot); + } + } + + internal void Ldlen() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ldlen"); + } + + ilGen.Emit(OpCodes.Ldlen); + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Conv.i4"); + } + + ilGen.Emit(OpCodes.Conv_I4); + } + + private OpCode GetLdelemOpCode(TypeCode typeCode) + { + switch (typeCode) + { + case TypeCode.Object: + case TypeCode.DBNull: + return OpCodes.Ldelem_Ref; // TypeCode.Object: + case TypeCode.Boolean: + return OpCodes.Ldelem_I1; // TypeCode.Boolean: + case TypeCode.Char: + return OpCodes.Ldelem_I2; // TypeCode.Char: + case TypeCode.SByte: + return OpCodes.Ldelem_I1; // TypeCode.SByte: + case TypeCode.Byte: + return OpCodes.Ldelem_U1; // TypeCode.Byte: + case TypeCode.Int16: + return OpCodes.Ldelem_I2; // TypeCode.Int16: + case TypeCode.UInt16: + return OpCodes.Ldelem_U2; // TypeCode.UInt16: + case TypeCode.Int32: + return OpCodes.Ldelem_I4; // TypeCode.Int32: + case TypeCode.UInt32: + return OpCodes.Ldelem_U4; // TypeCode.UInt32: + case TypeCode.Int64: + return OpCodes.Ldelem_I8; // TypeCode.Int64: + case TypeCode.UInt64: + return OpCodes.Ldelem_I8; // TypeCode.UInt64: + case TypeCode.Single: + return OpCodes.Ldelem_R4; // TypeCode.Single: + case TypeCode.Double: + return OpCodes.Ldelem_R8; // TypeCode.Double: + case TypeCode.String: + return OpCodes.Ldelem_Ref; // TypeCode.String: + default: + return OpCodes.Nop; + } + } + + internal void Ldelem(Type arrayElementType) + { + if (arrayElementType.IsEnum) + { + Ldelem(Enum.GetUnderlyingType(arrayElementType)); + } + else + { + OpCode opCode = GetLdelemOpCode(Type.GetTypeCode(arrayElementType)); + if (opCode.Equals(OpCodes.Nop)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported, DataContract.GetClrTypeFullName(arrayElementType)))); + } + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction(opCode.ToString()); + } + + ilGen.Emit(opCode); + EmitStackTop(arrayElementType); + } + } + internal void Ldelema(Type arrayElementType) + { + OpCode opCode = OpCodes.Ldelema; + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction(opCode.ToString()); + } + + ilGen.Emit(opCode, arrayElementType); + + EmitStackTop(arrayElementType); + } + + private OpCode GetStelemOpCode(TypeCode typeCode) + { + switch (typeCode) + { + case TypeCode.Object: + case TypeCode.DBNull: + return OpCodes.Stelem_Ref; // TypeCode.Object: + case TypeCode.Boolean: + return OpCodes.Stelem_I1; // TypeCode.Boolean: + case TypeCode.Char: + return OpCodes.Stelem_I2; // TypeCode.Char: + case TypeCode.SByte: + return OpCodes.Stelem_I1; // TypeCode.SByte: + case TypeCode.Byte: + return OpCodes.Stelem_I1; // TypeCode.Byte: + case TypeCode.Int16: + return OpCodes.Stelem_I2; // TypeCode.Int16: + case TypeCode.UInt16: + return OpCodes.Stelem_I2; // TypeCode.UInt16: + case TypeCode.Int32: + return OpCodes.Stelem_I4; // TypeCode.Int32: + case TypeCode.UInt32: + return OpCodes.Stelem_I4; // TypeCode.UInt32: + case TypeCode.Int64: + return OpCodes.Stelem_I8; // TypeCode.Int64: + case TypeCode.UInt64: + return OpCodes.Stelem_I8; // TypeCode.UInt64: + case TypeCode.Single: + return OpCodes.Stelem_R4; // TypeCode.Single: + case TypeCode.Double: + return OpCodes.Stelem_R8; // TypeCode.Double: + case TypeCode.String: + return OpCodes.Stelem_Ref; // TypeCode.String: + default: + return OpCodes.Nop; + } + } + + internal void Stelem(Type arrayElementType) + { + if (arrayElementType.IsEnum) + { + Stelem(Enum.GetUnderlyingType(arrayElementType)); + } + else + { + OpCode opCode = GetStelemOpCode(Type.GetTypeCode(arrayElementType)); + if (opCode.Equals(OpCodes.Nop)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported, DataContract.GetClrTypeFullName(arrayElementType)))); + } + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction(opCode.ToString()); + } + + EmitStackTop(arrayElementType); + ilGen.Emit(opCode); + } + } + + internal Label DefineLabel() + { + return ilGen.DefineLabel(); + } + + internal void MarkLabel(Label label) + { + ilGen.MarkLabel(label); + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceLabel(label.GetHashCode() + ":"); + } + } + + internal void Add() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Add"); + } + + ilGen.Emit(OpCodes.Add); + } + + internal void Subtract() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Sub"); + } + + ilGen.Emit(OpCodes.Sub); + } + + internal void And() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("And"); + } + + ilGen.Emit(OpCodes.And); + } + internal void Or() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Or"); + } + + ilGen.Emit(OpCodes.Or); + } + + internal void Not() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Not"); + } + + ilGen.Emit(OpCodes.Not); + } + + internal void Ret() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Ret"); + } + + ilGen.Emit(OpCodes.Ret); + } + + internal void Br(Label label) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Br " + label.GetHashCode()); + } + + ilGen.Emit(OpCodes.Br, label); + } + + internal void Blt(Label label) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Blt " + label.GetHashCode()); + } + + ilGen.Emit(OpCodes.Blt, label); + } + + internal void Brfalse(Label label) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Brfalse " + label.GetHashCode()); + } + + ilGen.Emit(OpCodes.Brfalse, label); + } + + internal void Brtrue(Label label) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Brtrue " + label.GetHashCode()); + } + + ilGen.Emit(OpCodes.Brtrue, label); + } + + + + internal void Pop() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Pop"); + } + + ilGen.Emit(OpCodes.Pop); + } + + internal void Dup() + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Dup"); + } + + ilGen.Emit(OpCodes.Dup); + } + + private void LoadThis(object thisObj, MethodInfo methodInfo) + { + if (thisObj != null && !methodInfo.IsStatic) + { + LoadAddress(thisObj); + ConvertAddress(GetVariableType(thisObj), methodInfo.DeclaringType); + } + } + + private void LoadParam(object arg, int oneBasedArgIndex, MethodBase methodInfo) + { + Load(arg); + if (arg != null) + { + ConvertValue(GetVariableType(arg), methodInfo.GetParameters()[oneBasedArgIndex - 1].ParameterType); + } + } + + private void InternalIf(bool negate) + { + IfState ifState = new IfState + { + EndIf = DefineLabel(), + ElseBegin = DefineLabel() + }; + if (negate) + { + Brtrue(ifState.ElseBegin); + } + else + { + Brfalse(ifState.ElseBegin); + } + + blockStack.Push(ifState); + } + + private OpCode GetConvOpCode(TypeCode typeCode) + { + switch (typeCode) + { + case TypeCode.Boolean: + return OpCodes.Conv_I1; // TypeCode.Boolean: + case TypeCode.Char: + return OpCodes.Conv_I2; // TypeCode.Char: + case TypeCode.SByte: + return OpCodes.Conv_I1; // TypeCode.SByte: + case TypeCode.Byte: + return OpCodes.Conv_U1; // TypeCode.Byte: + case TypeCode.Int16: + return OpCodes.Conv_I2; // TypeCode.Int16: + case TypeCode.UInt16: + return OpCodes.Conv_U2; // TypeCode.UInt16: + case TypeCode.Int32: + return OpCodes.Conv_I4; // TypeCode.Int32: + case TypeCode.UInt32: + return OpCodes.Conv_U4; // TypeCode.UInt32: + case TypeCode.Int64: + return OpCodes.Conv_I8; // TypeCode.Int64: + case TypeCode.UInt64: + return OpCodes.Conv_I8; // TypeCode.UInt64: + case TypeCode.Single: + return OpCodes.Conv_R4; // TypeCode.Single: + case TypeCode.Double: + return OpCodes.Conv_R8; // TypeCode.Double: + default: + return OpCodes.Nop; + } + } + + private void InternalConvert(Type source, Type target, bool isAddress) + { + if (target == source) + { + return; + } + + if (target.IsValueType) + { + if (source.IsValueType) + { + OpCode opCode = GetConvOpCode(Type.GetTypeCode(target)); + if (opCode.Equals(OpCodes.Nop)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoConversionPossibleTo, DataContract.GetClrTypeFullName(target)))); + } + else + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction(opCode.ToString()); + } + + ilGen.Emit(opCode); + } + } + else if (source.IsAssignableFrom(target)) + { + Unbox(target); + if (!isAddress) + { + Ldobj(target); + } + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source)))); + } + } + else if (target.IsAssignableFrom(source)) + { + if (source.IsValueType) + { + if (isAddress) + { + Ldobj(source); + } + + Box(source); + } + } + else if (source.IsAssignableFrom(target)) + { + //assert(source.IsValueType == false); + Castclass(target); + } + else if (target.IsInterface || source.IsInterface) + { + Castclass(target); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source)))); + } + } + + private IfState PopIfState() + { + object stackTop = blockStack.Pop(); + IfState ifState = stackTop as IfState; + if (ifState == null) + { + ThrowMismatchException(stackTop); + } + + return ifState; + } + + private void ThrowMismatchException(object expected) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExpectingEnd, expected.ToString()))); + } + + private Hashtable LocalNames + { + get + { + if (localNames == null) + { + localNames = new Hashtable(); + } + + return localNames; + } + } + + internal void EmitSourceInstruction(string line) + { + EmitSourceLine(" " + line); + } + + internal void EmitSourceLabel(string line) + { + EmitSourceLine(line); + } + + internal void EmitSourceComment(string comment) + { + EmitSourceInstruction("// " + comment); + } + + internal void EmitSourceLine(string line) + { + if (codeGenTrace != CodeGenTrace.None) + { + SerializationTrace.WriteInstruction(lineNo++, line); + } + + if (ilGen != null && codeGenTrace == CodeGenTrace.Tron) + { + ilGen.Emit(OpCodes.Ldstr, string.Format(CultureInfo.InvariantCulture, "{0:00000}: {1}", lineNo - 1, line)); + ilGen.Emit(OpCodes.Call, XmlFormatGeneratorStatics.TraceInstructionMethod); + } + } + + internal void EmitStackTop(Type stackTopType) + { + if (codeGenTrace != CodeGenTrace.Tron) + { + return; + } + + codeGenTrace = CodeGenTrace.None; + Dup(); + ToDebuggableString(stackTopType); + LocalBuilder topValue = DeclareLocal(Globals.TypeOfString, "topValue"); + Store(topValue); + Load("//value = "); + Load(topValue); + Concat2(); + Call(XmlFormatGeneratorStatics.TraceInstructionMethod); + codeGenTrace = CodeGenTrace.Tron; + } + + internal void ToString(Type type) + { + if (type != Globals.TypeOfString) + { + if (type.IsValueType) + { + Box(type); + } + Call(ObjectToString); + } + } + + internal void ToDebuggableString(Type type) + { + if (type.IsValueType) + { + Box(type); + Call(ObjectToString); + } + else + { + Dup(); + Load(null); + If(Cmp.EqualTo); + Pop(); + Load(""); + Else(); + if (type.IsArray) + { + LocalBuilder arrayVar = DeclareLocal(type, "arrayVar"); + Store(arrayVar); + Load("{ "); + LocalBuilder arrayValueString = DeclareLocal(typeof(string), "arrayValueString"); + Store(arrayValueString); + LocalBuilder i = DeclareLocal(typeof(int), "i"); + For(i, 0, arrayVar); + Load(arrayValueString); + LoadArrayElement(arrayVar, i); + ToDebuggableString(arrayVar.LocalType.GetElementType()); + Load(", "); + Concat3(); + Store(arrayValueString); + EndFor(); + Load(arrayValueString); + Load("}"); + Concat2(); + } + else + { + Call(ObjectToString); + } + + EndIf(); + } + } + + internal void Concat2() + { + Call(StringConcat2); + } + + internal void Concat3() + { + Call(StringConcat3); + } + + internal Label[] Switch(int labelCount) + { + SwitchState switchState = new SwitchState(DefineLabel(), DefineLabel()); + Label[] caseLabels = new Label[labelCount]; + for (int i = 0; i < caseLabels.Length; i++) + { + caseLabels[i] = DefineLabel(); + } + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("switch ("); + foreach (Label l in caseLabels) + { + EmitSourceInstruction(" " + l.GetHashCode()); + } + + EmitSourceInstruction(") {"); + } + ilGen.Emit(OpCodes.Switch, caseLabels); + Br(switchState.DefaultLabel); + blockStack.Push(switchState); + return caseLabels; + } + internal void Case(Label caseLabel1, string caseLabelName) + { + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("case " + caseLabelName + "{"); + } + + MarkLabel(caseLabel1); + } + + internal void EndCase() + { + object stackTop = blockStack.Peek(); + SwitchState switchState = stackTop as SwitchState; + if (switchState == null) + { + ThrowMismatchException(stackTop); + } + + Br(switchState.EndOfSwitchLabel); + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("} //end case "); + } + } + + internal void DefaultCase() + { + object stackTop = blockStack.Peek(); + SwitchState switchState = stackTop as SwitchState; + if (switchState == null) + { + ThrowMismatchException(stackTop); + } + + MarkLabel(switchState.DefaultLabel); + switchState.DefaultDefined = true; + } + + internal void EndSwitch() + { + object stackTop = blockStack.Pop(); + SwitchState switchState = stackTop as SwitchState; + if (switchState == null) + { + ThrowMismatchException(stackTop); + } + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("} //end switch"); + } + + if (!switchState.DefaultDefined) + { + MarkLabel(switchState.DefaultLabel); + } + + MarkLabel(switchState.EndOfSwitchLabel); + } + + internal void CallStringFormat(string msg, params object[] values) + { + NewArray(typeof(object), values.Length); + if (stringFormatArray == null) + { + stringFormatArray = DeclareLocal(typeof(object[]), "stringFormatArray"); + } + + Stloc(stringFormatArray); + for (int i = 0; i < values.Length; i++) + { + StoreArrayElement(stringFormatArray, i, values[i]); + } + + Load(msg); + Load(stringFormatArray); + Call(StringFormat); + } + + private static readonly MethodInfo stringLength = typeof(string).GetProperty("Length").GetGetMethod(); + internal void ElseIfIsEmptyString(LocalBuilder strLocal) + { + IfState ifState = (IfState)blockStack.Pop(); + Br(ifState.EndIf); + MarkLabel(ifState.ElseBegin); + + Load(strLocal); + Call(stringLength); + Load(0); + ifState.ElseBegin = DefineLabel(); + + if (codeGenTrace != CodeGenTrace.None) + { + EmitSourceInstruction("Branch if " + GetCmpInverse(Cmp.EqualTo).ToString() + " to " + ifState.ElseBegin.GetHashCode().ToString(NumberFormatInfo.InvariantInfo)); + } + + ilGen.Emit(GetBranchCode(Cmp.EqualTo), ifState.ElseBegin); + blockStack.Push(ifState); + } + + internal void IfNotIsEmptyString(LocalBuilder strLocal) + { + Load(strLocal); + Call(stringLength); + Load(0); + If(Cmp.NotEqualTo); + } + + internal void BeginWhileCondition() + { + Label startWhile = DefineLabel(); + MarkLabel(startWhile); + blockStack.Push(startWhile); + } + + internal void BeginWhileBody(Cmp cmpOp) + { + Label startWhile = (Label)blockStack.Pop(); + If(cmpOp); + blockStack.Push(startWhile); + } + + internal void EndWhile() + { + Label startWhile = (Label)blockStack.Pop(); + Br(startWhile); + EndIf(); + } + } + + + internal class ArgBuilder + { + internal int Index; + internal Type ArgType; + internal ArgBuilder(int index, Type argType) + { + Index = index; + ArgType = argType; + } + } + + internal class ForState + { + private readonly LocalBuilder indexVar; + private Label beginLabel; + private Label testLabel; + private Label endLabel; + private bool requiresEndLabel; + private readonly object end; + + internal ForState(LocalBuilder indexVar, Label beginLabel, Label testLabel, object end) + { + this.indexVar = indexVar; + this.beginLabel = beginLabel; + this.testLabel = testLabel; + this.end = end; + } + + internal LocalBuilder Index => indexVar; + + internal Label BeginLabel => beginLabel; + + internal Label TestLabel => testLabel; + + internal Label EndLabel + { + get => endLabel; + set => endLabel = value; + } + + internal bool RequiresEndLabel + { + get => requiresEndLabel; + set => requiresEndLabel = value; + } + + internal object End => end; + } + + internal enum Cmp + { + LessThan, + EqualTo, + LessThanOrEqualTo, + GreaterThan, + NotEqualTo, + GreaterThanOrEqualTo + } + + internal class IfState + { + private Label elseBegin; + private Label endIf; + + internal Label EndIf + { + get => endIf; + set => endIf = value; + } + + internal Label ElseBegin + { + get => elseBegin; + set => elseBegin = value; + } + + } + internal class SwitchState + { + private Label defaultLabel; + private Label endOfSwitchLabel; + private bool defaultDefined; + internal SwitchState(Label defaultLabel, Label endOfSwitchLabel) + { + this.defaultLabel = defaultLabel; + this.endOfSwitchLabel = endOfSwitchLabel; + defaultDefined = false; + } + internal Label DefaultLabel => defaultLabel; + + internal Label EndOfSwitchLabel => endOfSwitchLabel; + internal bool DefaultDefined + { + get => defaultDefined; + set => defaultDefined = value; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataContract.cs new file mode 100644 index 0000000..3bd16f9 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataContract.cs @@ -0,0 +1,1343 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Security; +using System.Threading; +using System.Xml; +using CollectionDataContractAttribute = System.Runtime.Serialization.CollectionDataContractAttribute; +using DataContractAttribute = System.Runtime.Serialization.DataContractAttribute; +using DataMemberAttribute = System.Runtime.Serialization.DataMemberAttribute; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + [DataContract(Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")] + internal struct KeyValue + { + private K _key; + private V _value; + + internal KeyValue(K key, V value) + { + _key = key; + _value = value; + } + + [DataMember(IsRequired = true)] + public K Key + { + get => _key; + set => _key = value; + } + + [DataMember(IsRequired = true)] + public V Value + { + get => _value; + set => _value = value; + } + } + + internal enum CollectionKind : byte + { + None, + GenericDictionary, + Dictionary, + GenericList, + GenericCollection, + List, + GenericEnumerable, + Collection, + Enumerable, + Array, + } + + internal sealed class CollectionDataContract : DataContract + { + private XmlDictionaryString collectionItemName; + + private XmlDictionaryString childElementNamespace; + + private DataContract itemContract; + + private CollectionDataContractCriticalHelper helper; + + internal CollectionDataContract(CollectionKind kind) + : base(new CollectionDataContractCriticalHelper(kind)) + { + InitCollectionDataContract(this); + } + + internal CollectionDataContract(Type type) + : base(new CollectionDataContractCriticalHelper(type)) + { + InitCollectionDataContract(this); + } + + internal CollectionDataContract(Type type, DataContract itemContract) + : base(new CollectionDataContractCriticalHelper(type, itemContract)) + { + InitCollectionDataContract(this); + } + + + private CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string serializationExceptionMessage, string deserializationExceptionMessage) + : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage)) + { + InitCollectionDataContract(GetSharedTypeContract(type)); + } + + private CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor) + : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, addMethod, constructor)) + { + InitCollectionDataContract(GetSharedTypeContract(type)); + } + + private CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor, bool isConstructorCheckRequired) + : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, addMethod, constructor, isConstructorCheckRequired)) + { + InitCollectionDataContract(GetSharedTypeContract(type)); + } + + private CollectionDataContract(Type type, string invalidCollectionInSharedContractMessage) + : base(new CollectionDataContractCriticalHelper(type, invalidCollectionInSharedContractMessage)) + { + InitCollectionDataContract(GetSharedTypeContract(type)); + } + + private void InitCollectionDataContract(DataContract sharedTypeContract) + { + helper = base.Helper as CollectionDataContractCriticalHelper; + collectionItemName = helper.CollectionItemName; + if (helper.Kind == CollectionKind.Dictionary || helper.Kind == CollectionKind.GenericDictionary) + { + itemContract = helper.ItemContract; + } + helper.SharedTypeContract = sharedTypeContract; + } + + private void InitSharedTypeContract() + { + } + + private static Type[] KnownInterfaces => CollectionDataContractCriticalHelper.KnownInterfaces; + + internal CollectionKind Kind => helper.Kind; + + internal Type ItemType => helper.ItemType; + + public DataContract ItemContract + { + get => itemContract ?? helper.ItemContract; + + set + { + itemContract = value; + helper.ItemContract = value; + } + } + + internal DataContract SharedTypeContract => helper.SharedTypeContract; + + internal string ItemName + { + get => helper.ItemName; + set => helper.ItemName = value; + } + + public XmlDictionaryString CollectionItemName => collectionItemName; + + internal string KeyName + { + get => helper.KeyName; + + set => helper.KeyName = value; + } + + internal string ValueName + { + get => helper.ValueName; + set => helper.ValueName = value; + } + + internal bool IsDictionary => KeyName != null; + + public XmlDictionaryString ChildElementNamespace + { + get + { + if (childElementNamespace == null) + { + lock (this) + { + if (childElementNamespace == null) + { + if (helper.ChildElementNamespace == null && !IsDictionary) + { + XmlDictionaryString tempChildElementNamespace = ClassDataContract.GetChildNamespaceToDeclare(this, ItemType, new XmlDictionary()); + Thread.MemoryBarrier(); + helper.ChildElementNamespace = tempChildElementNamespace; + } + childElementNamespace = helper.ChildElementNamespace; + } + } + } + return childElementNamespace; + } + } + + internal bool IsItemTypeNullable + { + get => helper.IsItemTypeNullable; + set => helper.IsItemTypeNullable = value; + } + + internal bool IsConstructorCheckRequired + { + get => helper.IsConstructorCheckRequired; + set => helper.IsConstructorCheckRequired = value; + } + + internal MethodInfo GetEnumeratorMethod => helper.GetEnumeratorMethod; + + internal MethodInfo AddMethod => helper.AddMethod; + + internal ConstructorInfo Constructor => helper.Constructor; + + internal override DataContractDictionary KnownDataContracts + { + get => helper.KnownDataContracts; + set => helper.KnownDataContracts = value; + } + + internal string InvalidCollectionInSharedContractMessage => helper.InvalidCollectionInSharedContractMessage; + + internal string SerializationExceptionMessage => helper.SerializationExceptionMessage; + + internal string DeserializationExceptionMessage => helper.DeserializationExceptionMessage; + + internal bool IsReadOnlyContract => DeserializationExceptionMessage != null; + + private bool ItemNameSetExplicit => helper.ItemNameSetExplicit; + + internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate + { + get + { + if (helper.XmlFormatWriterDelegate == null) + { + lock (this) + { + if (helper.XmlFormatWriterDelegate == null) + { + XmlFormatCollectionWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateCollectionWriter(this); + Thread.MemoryBarrier(); + helper.XmlFormatWriterDelegate = tempDelegate; + } + } + } + return helper.XmlFormatWriterDelegate; + } + } + + internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate + { + get + { + if (helper.XmlFormatReaderDelegate == null) + { + lock (this) + { + if (helper.XmlFormatReaderDelegate == null) + { + if (IsReadOnlyContract) + { + ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/); + } + XmlFormatCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateCollectionReader(this); + Thread.MemoryBarrier(); + helper.XmlFormatReaderDelegate = tempDelegate; + } + } + } + return helper.XmlFormatReaderDelegate; + } + } + + internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate + { + get + { + if (helper.XmlFormatGetOnlyCollectionReaderDelegate == null) + { + lock (this) + { + if (helper.XmlFormatGetOnlyCollectionReaderDelegate == null) + { + if (UnderlyingType.IsInterface && (Kind == CollectionKind.Enumerable || Kind == CollectionKind.Collection || Kind == CollectionKind.GenericEnumerable)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GetOnlyCollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + if (IsReadOnlyContract) + { + ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/); + } + Fx.Assert(AddMethod != null || Kind == CollectionKind.Array, "Add method cannot be null if the collection is being used as a get-only property"); + XmlFormatGetOnlyCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateGetOnlyCollectionReader(this); + Thread.MemoryBarrier(); + helper.XmlFormatGetOnlyCollectionReaderDelegate = tempDelegate; + } + } + } + return helper.XmlFormatGetOnlyCollectionReaderDelegate; + } + } + + private class CollectionDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private static Type[] _knownInterfaces; + private Type itemType; + private bool isItemTypeNullable; + private CollectionKind kind; + private readonly MethodInfo getEnumeratorMethod, addMethod; + private readonly ConstructorInfo constructor; + private readonly string serializationExceptionMessage, deserializationExceptionMessage; + private DataContract itemContract; + private DataContract sharedTypeContract; + private DataContractDictionary knownDataContracts; + private bool isKnownTypeAttributeChecked; + private string itemName; + private bool itemNameSetExplicit; + private XmlDictionaryString collectionItemName; + private string keyName; + private string valueName; + private XmlDictionaryString childElementNamespace; + private readonly string invalidCollectionInSharedContractMessage; + private XmlFormatCollectionReaderDelegate xmlFormatReaderDelegate; + private XmlFormatGetOnlyCollectionReaderDelegate xmlFormatGetOnlyCollectionReaderDelegate; + private XmlFormatCollectionWriterDelegate xmlFormatWriterDelegate; + private bool isConstructorCheckRequired = false; + + internal static Type[] KnownInterfaces + { + get + { + if (_knownInterfaces == null) + { + // Listed in priority order + _knownInterfaces = new Type[] + { + Globals.TypeOfIDictionaryGeneric, + Globals.TypeOfIDictionary, + Globals.TypeOfIListGeneric, + Globals.TypeOfICollectionGeneric, + Globals.TypeOfIList, + Globals.TypeOfIEnumerableGeneric, + Globals.TypeOfICollection, + Globals.TypeOfIEnumerable + }; + } + return _knownInterfaces; + } + } + + private void Init(CollectionKind kind, Type itemType, CollectionDataContractAttribute collectionContractAttribute) + { + this.kind = kind; + if (itemType != null) + { + this.itemType = itemType; + isItemTypeNullable = DataContract.IsTypeNullable(itemType); + + bool isDictionary = (kind == CollectionKind.Dictionary || kind == CollectionKind.GenericDictionary); + string itemName = null, keyName = null, valueName = null; + if (collectionContractAttribute != null) + { + if (collectionContractAttribute.IsItemNameSetExplicitly) + { + if (collectionContractAttribute.ItemName == null || collectionContractAttribute.ItemName.Length == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractItemName, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + itemName = DataContract.EncodeLocalName(collectionContractAttribute.ItemName); + itemNameSetExplicit = true; + } + if (collectionContractAttribute.IsKeyNameSetExplicitly) + { + if (collectionContractAttribute.KeyName == null || collectionContractAttribute.KeyName.Length == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractKeyName, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + if (!isDictionary) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractKeyNoDictionary, DataContract.GetClrTypeFullName(UnderlyingType), collectionContractAttribute.KeyName))); + } + + keyName = DataContract.EncodeLocalName(collectionContractAttribute.KeyName); + } + if (collectionContractAttribute.IsValueNameSetExplicitly) + { + if (collectionContractAttribute.ValueName == null || collectionContractAttribute.ValueName.Length == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractValueName, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + if (!isDictionary) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractValueNoDictionary, DataContract.GetClrTypeFullName(UnderlyingType), collectionContractAttribute.ValueName))); + } + + valueName = DataContract.EncodeLocalName(collectionContractAttribute.ValueName); + } + } + + XmlDictionary dictionary = isDictionary ? new XmlDictionary(5) : new XmlDictionary(3); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); + this.itemName = itemName ?? DataContract.GetStableName(DataContract.UnwrapNullableType(itemType)).Name; + collectionItemName = dictionary.Add(this.itemName); + if (isDictionary) + { + this.keyName = keyName ?? Globals.KeyLocalName; + this.valueName = valueName ?? Globals.ValueLocalName; + } + } + if (collectionContractAttribute != null) + { + IsReference = collectionContractAttribute.IsReference; + } + } + + internal CollectionDataContractCriticalHelper(CollectionKind kind) + : base() + { + Init(kind, null, null); + } + + // array + internal CollectionDataContractCriticalHelper(Type type) + : base(type) + { + if (type == Globals.TypeOfArray) + { + type = Globals.TypeOfObjectArray; + } + + if (type.GetArrayRank() > 1) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); + } + + StableName = DataContract.GetStableName(type); + Init(CollectionKind.Array, type.GetElementType(), null); + } + + // array + internal CollectionDataContractCriticalHelper(Type type, DataContract itemContract) + : base(type) + { + if (type.GetArrayRank() > 1) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); + } + + StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace); + this.itemContract = itemContract; + Init(CollectionKind.Array, type.GetElementType(), null); + } + + // read-only collection + internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string serializationExceptionMessage, string deserializationExceptionMessage) + : base(type) + { + if (getEnumeratorMethod == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveGetEnumeratorMethod, DataContract.GetClrTypeFullName(type)))); + } + + if (itemType == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveItemType, DataContract.GetClrTypeFullName(type)))); + } + + StableName = DataContract.GetCollectionStableName(type, itemType, out CollectionDataContractAttribute collectionContractAttribute); + + Init(kind, itemType, collectionContractAttribute); + this.getEnumeratorMethod = getEnumeratorMethod; + this.serializationExceptionMessage = serializationExceptionMessage; + this.deserializationExceptionMessage = deserializationExceptionMessage; + } + + // collection + internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor) + : this(type, kind, itemType, getEnumeratorMethod, null, (string)null) + { + if (addMethod == null && !type.IsInterface) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(type)))); + } + + this.addMethod = addMethod; + this.constructor = constructor; + } + + // collection + internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor, bool isConstructorCheckRequired) + : this(type, kind, itemType, getEnumeratorMethod, addMethod, constructor) + { + this.isConstructorCheckRequired = isConstructorCheckRequired; + } + + internal CollectionDataContractCriticalHelper(Type type, string invalidCollectionInSharedContractMessage) + : base(type) + { + Init(CollectionKind.Collection, null /*itemType*/, null); + this.invalidCollectionInSharedContractMessage = invalidCollectionInSharedContractMessage; + } + + internal CollectionKind Kind => kind; + + internal Type ItemType => itemType; + + internal DataContract ItemContract + { + get + { + if (itemContract == null && UnderlyingType != null) + { + if (IsDictionary) + { + if (string.CompareOrdinal(KeyName, ValueName) == 0) + { + DataContract.ThrowInvalidDataContractException( + SR.Format(SR.DupKeyValueName, DataContract.GetClrTypeFullName(UnderlyingType), KeyName), + UnderlyingType); + } + itemContract = ClassDataContract.CreateClassDataContractForKeyValue(ItemType, Namespace, new string[] { KeyName, ValueName }); + // Ensure that DataContract gets added to the static DataContract cache for dictionary items + DataContract.GetDataContract(ItemType); + } + else + { + itemContract = DataContract.GetDataContract(ItemType); + } + } + return itemContract; + } + set => itemContract = value; + } + + internal DataContract SharedTypeContract + { + get => sharedTypeContract; + set => sharedTypeContract = value; + } + + internal string ItemName + { + get => itemName; + set => itemName = value; + } + + internal bool IsConstructorCheckRequired + { + get => isConstructorCheckRequired; + set => isConstructorCheckRequired = value; + } + + public XmlDictionaryString CollectionItemName => collectionItemName; + + internal string KeyName + { + get => keyName; + set => keyName = value; + } + + internal string ValueName + { + get => valueName; + set => valueName = value; + } + + internal bool IsDictionary => KeyName != null; + + public string SerializationExceptionMessage => serializationExceptionMessage; + + public string DeserializationExceptionMessage => deserializationExceptionMessage; + + public XmlDictionaryString ChildElementNamespace + { + get => childElementNamespace; + set => childElementNamespace = value; + } + + internal bool IsItemTypeNullable + { + get => isItemTypeNullable; + set => isItemTypeNullable = value; + } + + internal MethodInfo GetEnumeratorMethod => getEnumeratorMethod; + + internal MethodInfo AddMethod => addMethod; + + internal ConstructorInfo Constructor => constructor; + + internal override DataContractDictionary KnownDataContracts + { + get + { + if (!isKnownTypeAttributeChecked && UnderlyingType != null) + { + lock (this) + { + if (!isKnownTypeAttributeChecked) + { + knownDataContracts = DataContract.ImportKnownTypeAttributes(UnderlyingType); + Thread.MemoryBarrier(); + isKnownTypeAttributeChecked = true; + } + } + } + return knownDataContracts; + } + set => knownDataContracts = value; + } + + internal string InvalidCollectionInSharedContractMessage => invalidCollectionInSharedContractMessage; + + internal bool ItemNameSetExplicit => itemNameSetExplicit; + + internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate + { + get => xmlFormatWriterDelegate; + set => xmlFormatWriterDelegate = value; + } + + internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate + { + get => xmlFormatReaderDelegate; + set => xmlFormatReaderDelegate = value; + } + + internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate + { + get => xmlFormatGetOnlyCollectionReaderDelegate; + set => xmlFormatGetOnlyCollectionReaderDelegate = value; + } + } + + private DataContract GetSharedTypeContract(Type type) + { + if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) + { + return this; + } + // ClassDataContract.IsNonAttributedTypeValidForSerialization does not need to be called here. It should + // never pass because it returns false for types that implement any of CollectionDataContract.KnownInterfaces + if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false)) + { + return new ClassDataContract(type); + } + return null; + } + + internal static bool IsCollectionInterface(Type type) + { + if (type.IsGenericType) + { + type = type.GetGenericTypeDefinition(); + } + + return ((IList)KnownInterfaces).Contains(type); + } + + internal static bool IsCollection(Type type) + { + return IsCollection(type, out Type itemType); + } + + internal static bool IsCollection(Type type, out Type itemType) + { + return IsCollectionHelper(type, out itemType, true /*constructorRequired*/); + } + + internal static bool IsCollection(Type type, bool constructorRequired, bool skipIfReadOnlyContract) + { + return IsCollectionHelper(type, out Type itemType, constructorRequired, skipIfReadOnlyContract); + } + + private static bool IsCollectionHelper(Type type, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false) + { + if (type.IsArray && DataContract.GetBuiltInDataContract(type) == null) + { + itemType = type.GetElementType(); + return true; + } + return IsCollectionOrTryCreate(type, false /*tryCreate*/, out DataContract dataContract, out itemType, constructorRequired, skipIfReadOnlyContract); + } + + internal static bool TryCreate(Type type, out DataContract dataContract) + { + return IsCollectionOrTryCreate(type, true /*tryCreate*/, out dataContract, out Type itemType, true /*constructorRequired*/); + } + + internal static bool TryCreateGetOnlyCollectionDataContract(Type type, out DataContract dataContract) + { + if (type.IsArray) + { + dataContract = new CollectionDataContract(type); + return true; + } + else + { + return IsCollectionOrTryCreate(type, true /*tryCreate*/, out dataContract, out Type itemType, false /*constructorRequired*/); + } + } + + internal static MethodInfo GetTargetMethodWithName(string name, Type type, Type interfaceType) + { + InterfaceMapping mapping = type.GetInterfaceMap(interfaceType); + for (int i = 0; i < mapping.TargetMethods.Length; i++) + { + if (mapping.InterfaceMethods[i].Name == name) + { + return mapping.InterfaceMethods[i]; + } + } + return null; + } + + private static bool IsArraySegment(Type t) + { + return t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(ArraySegment<>)); + } + + private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataContract dataContract, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false) + { + dataContract = null; + itemType = Globals.TypeOfObject; + + if (DataContract.GetBuiltInDataContract(type) != null) + { + return HandleIfInvalidCollection(type, tryCreate, false/*hasCollectionDataContract*/, false/*isBaseTypeCollection*/, + SR.CollectionTypeCannotBeBuiltIn, null, ref dataContract); + } + MethodInfo addMethod, getEnumeratorMethod; + bool hasCollectionDataContract = IsCollectionDataContract(type); + bool isReadOnlyContract = false; + string serializationExceptionMessage = null, deserializationExceptionMessage = null; + Type baseType = type.BaseType; + bool isBaseTypeCollection = (baseType != null && baseType != Globals.TypeOfObject + && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) ? IsCollection(baseType) : false; + + // Avoid creating an invalid collection contract for Serializable types since we can create a ClassDataContract instead + bool createContractWithException = isBaseTypeCollection && !type.IsSerializable; + + if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) + { + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException, + SR.CollectionTypeCannotHaveDataContract, null, ref dataContract); + } + + if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) || IsArraySegment(type)) + { + return false; + } + + if (!Globals.TypeOfIEnumerable.IsAssignableFrom(type)) + { + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException, + SR.CollectionTypeIsNotIEnumerable, null, ref dataContract); + } + if (type.IsInterface) + { + Type interfaceTypeToCheck = type.IsGenericType ? type.GetGenericTypeDefinition() : type; + Type[] knownInterfaces = KnownInterfaces; + for (int i = 0; i < knownInterfaces.Length; i++) + { + if (knownInterfaces[i] == interfaceTypeToCheck) + { + addMethod = null; + if (type.IsGenericType) + { + Type[] genericArgs = type.GetGenericArguments(); + if (interfaceTypeToCheck == Globals.TypeOfIDictionaryGeneric) + { + itemType = Globals.TypeOfKeyValue.MakeGenericType(genericArgs); + addMethod = type.GetMethod(Globals.AddMethodName); + getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(genericArgs)).GetMethod(Globals.GetEnumeratorMethodName); + } + else + { + itemType = genericArgs[0]; + if (interfaceTypeToCheck == Globals.TypeOfICollectionGeneric || interfaceTypeToCheck == Globals.TypeOfIListGeneric) + { + addMethod = Globals.TypeOfICollectionGeneric.MakeGenericType(itemType).GetMethod(Globals.AddMethodName); + } + getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(itemType).GetMethod(Globals.GetEnumeratorMethodName); + } + } + else + { + if (interfaceTypeToCheck == Globals.TypeOfIDictionary) + { + itemType = typeof(KeyValue); + addMethod = type.GetMethod(Globals.AddMethodName); + } + else + { + itemType = Globals.TypeOfObject; + if (interfaceTypeToCheck == Globals.TypeOfIList) + { + addMethod = Globals.TypeOfIList.GetMethod(Globals.AddMethodName); + } + } + getEnumeratorMethod = Globals.TypeOfIEnumerable.GetMethod(Globals.GetEnumeratorMethodName); + } + if (tryCreate) + { + dataContract = new CollectionDataContract(type, (CollectionKind)(i + 1), itemType, getEnumeratorMethod, addMethod, null/*defaultCtor*/); + } + + return true; + } + } + } + ConstructorInfo defaultCtor = null; + if (!type.IsValueType) + { + defaultCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null); + if (defaultCtor == null && constructorRequired) + { + // All collection types could be considered read-only collections except collection types that are marked [Serializable]. + // Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons. + // DataContract types and POCO types cannot be collection types, so they don't need to be factored in + if (type.IsSerializable) + { + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException, + SR.CollectionTypeDoesNotHaveDefaultCtor, null, ref dataContract); + } + else + { + isReadOnlyContract = true; + GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveDefaultCtor, null, out serializationExceptionMessage, out deserializationExceptionMessage); + } + } + } + + Type knownInterfaceType = null; + CollectionKind kind = CollectionKind.None; + bool multipleDefinitions = false; + Type[] interfaceTypes = type.GetInterfaces(); + foreach (Type interfaceType in interfaceTypes) + { + Type interfaceTypeToCheck = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType; + Type[] knownInterfaces = KnownInterfaces; + for (int i = 0; i < knownInterfaces.Length; i++) + { + if (knownInterfaces[i] == interfaceTypeToCheck) + { + CollectionKind currentKind = (CollectionKind)(i + 1); + if (kind == CollectionKind.None || currentKind < kind) + { + kind = currentKind; + knownInterfaceType = interfaceType; + multipleDefinitions = false; + } + else if ((kind & currentKind) == currentKind) + { + multipleDefinitions = true; + } + + break; + } + } + } + + if (kind == CollectionKind.None) + { + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException, + SR.CollectionTypeIsNotIEnumerable, null, ref dataContract); + } + + if (kind == CollectionKind.Enumerable || kind == CollectionKind.Collection || kind == CollectionKind.GenericEnumerable) + { + if (multipleDefinitions) + { + knownInterfaceType = Globals.TypeOfIEnumerable; + } + + itemType = knownInterfaceType.IsGenericType ? knownInterfaceType.GetGenericArguments()[0] : Globals.TypeOfObject; + GetCollectionMethods(type, knownInterfaceType, new Type[] { itemType }, + false /*addMethodOnInterface*/, + out getEnumeratorMethod, out addMethod); + if (addMethod == null) + { + // All collection types could be considered read-only collections except collection types that are marked [Serializable]. + // Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons. + // DataContract types and POCO types cannot be collection types, so they don't need to be factored in. + if (type.IsSerializable || skipIfReadOnlyContract) + { + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException && !skipIfReadOnlyContract, + SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), ref dataContract); + } + else + { + isReadOnlyContract = true; + GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), out serializationExceptionMessage, out deserializationExceptionMessage); + } + } + + if (tryCreate) + { + dataContract = isReadOnlyContract ? + new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) : + new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired); + } + } + else + { + if (multipleDefinitions) + { + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException, + SR.CollectionTypeHasMultipleDefinitionsOfInterface, KnownInterfaces[(int)kind - 1].Name, ref dataContract); + } + Type[] addMethodTypeArray = null; + switch (kind) + { + case CollectionKind.GenericDictionary: + addMethodTypeArray = knownInterfaceType.GetGenericArguments(); + bool isOpenGeneric = knownInterfaceType.IsGenericTypeDefinition + || (addMethodTypeArray[0].IsGenericParameter && addMethodTypeArray[1].IsGenericParameter); + itemType = isOpenGeneric ? Globals.TypeOfKeyValue : Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray); + break; + case CollectionKind.Dictionary: + addMethodTypeArray = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject }; + itemType = Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray); + break; + case CollectionKind.GenericList: + case CollectionKind.GenericCollection: + addMethodTypeArray = knownInterfaceType.GetGenericArguments(); + itemType = addMethodTypeArray[0]; + break; + case CollectionKind.List: + itemType = Globals.TypeOfObject; + addMethodTypeArray = new Type[] { itemType }; + break; + } + + if (tryCreate) + { + GetCollectionMethods(type, knownInterfaceType, addMethodTypeArray, + true /*addMethodOnInterface*/, + out getEnumeratorMethod, out addMethod); + dataContract = isReadOnlyContract ? + new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) : + new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired); + } + } + + return !(isReadOnlyContract && skipIfReadOnlyContract); + } + + internal static bool IsCollectionDataContract(Type type) + { + return type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false); + } + + private static bool HandleIfInvalidCollection(Type type, bool tryCreate, bool hasCollectionDataContract, bool createContractWithException, string message, string param, ref DataContract dataContract) + { + if (hasCollectionDataContract) + { + if (tryCreate) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(GetInvalidCollectionMessage(message, SR.Format(SR.InvalidCollectionDataContract, DataContract.GetClrTypeFullName(type)), param))); + } + + return true; + } + + if (createContractWithException) + { + if (tryCreate) + { + dataContract = new CollectionDataContract(type, GetInvalidCollectionMessage(message, SR.Format(SR.InvalidCollectionType, DataContract.GetClrTypeFullName(type)), param)); + } + + return true; + } + + return false; + } + + private static void GetReadOnlyCollectionExceptionMessages(Type type, bool hasCollectionDataContract, string message, string param, out string serializationExceptionMessage, out string deserializationExceptionMessage) + { + serializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(hasCollectionDataContract ? SR.InvalidCollectionDataContract : SR.InvalidCollectionType, DataContract.GetClrTypeFullName(type)), param); + deserializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(SR.ReadOnlyCollectionDeserialization, DataContract.GetClrTypeFullName(type)), param); + } + + private static string GetInvalidCollectionMessage(string message, string nestedMessage, string param) + { + return (param == null) ? SR.Format(message, nestedMessage) : SR.Format(message, nestedMessage, param); + } + + private static void FindCollectionMethodsOnInterface(Type type, Type interfaceType, ref MethodInfo addMethod, ref MethodInfo getEnumeratorMethod) + { + InterfaceMapping mapping = type.GetInterfaceMap(interfaceType); + for (int i = 0; i < mapping.TargetMethods.Length; i++) + { + if (mapping.InterfaceMethods[i].Name == Globals.AddMethodName) + { + addMethod = mapping.InterfaceMethods[i]; + } + else if (mapping.InterfaceMethods[i].Name == Globals.GetEnumeratorMethodName) + { + getEnumeratorMethod = mapping.InterfaceMethods[i]; + } + } + } + + private static void GetCollectionMethods(Type type, Type interfaceType, Type[] addMethodTypeArray, bool addMethodOnInterface, out MethodInfo getEnumeratorMethod, out MethodInfo addMethod) + { + addMethod = getEnumeratorMethod = null; + + if (addMethodOnInterface) + { + addMethod = type.GetMethod(Globals.AddMethodName, BindingFlags.Instance | BindingFlags.Public, null, addMethodTypeArray, null); + if (addMethod == null || addMethod.GetParameters()[0].ParameterType != addMethodTypeArray[0]) + { + FindCollectionMethodsOnInterface(type, interfaceType, ref addMethod, ref getEnumeratorMethod); + if (addMethod == null) + { + Type[] parentInterfaceTypes = interfaceType.GetInterfaces(); + foreach (Type parentInterfaceType in parentInterfaceTypes) + { + if (IsKnownInterface(parentInterfaceType)) + { + FindCollectionMethodsOnInterface(type, parentInterfaceType, ref addMethod, ref getEnumeratorMethod); + if (addMethod == null) + { + break; + } + } + } + } + } + } + else + { + // GetMethod returns Add() method with parameter closest matching T in assignability/inheritance chain + addMethod = type.GetMethod(Globals.AddMethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, addMethodTypeArray, null); + } + + if (getEnumeratorMethod == null) + { + getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + if (getEnumeratorMethod == null || !Globals.TypeOfIEnumerator.IsAssignableFrom(getEnumeratorMethod.ReturnType)) + { + Type ienumerableInterface = interfaceType.GetInterface("System.Collections.Generic.IEnumerable*"); + if (ienumerableInterface == null) + { + ienumerableInterface = Globals.TypeOfIEnumerable; + } + + getEnumeratorMethod = GetTargetMethodWithName(Globals.GetEnumeratorMethodName, type, ienumerableInterface); + } + } + } + + private static bool IsKnownInterface(Type type) + { + Type typeToCheck = type.IsGenericType ? type.GetGenericTypeDefinition() : type; + foreach (Type knownInterfaceType in KnownInterfaces) + { + if (typeToCheck == knownInterfaceType) + { + return true; + } + } + return false; + } + + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + if (boundContracts.TryGetValue(this, out DataContract boundContract)) + { + return boundContract; + } + + CollectionDataContract boundCollectionContract = new CollectionDataContract(Kind); + boundContracts.Add(this, boundCollectionContract); + boundCollectionContract.ItemContract = ItemContract.BindGenericParameters(paramContracts, boundContracts); + boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType; + boundCollectionContract.ItemName = ItemNameSetExplicit ? ItemName : boundCollectionContract.ItemContract.StableName.Name; + boundCollectionContract.KeyName = KeyName; + boundCollectionContract.ValueName = ValueName; + boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), paramContracts)), + IsCollectionDataContract(UnderlyingType) ? StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace)); + return boundCollectionContract; + } + + internal override DataContract GetValidContract(SerializationMode mode) + { + if (mode == SerializationMode.SharedType) + { + if (SharedTypeContract == null) + { + DataContract.ThrowTypeNotSerializable(UnderlyingType); + } + + return SharedTypeContract; + } + + ThrowIfInvalid(); + return this; + } + + private void ThrowIfInvalid() + { + if (InvalidCollectionInSharedContractMessage != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(InvalidCollectionInSharedContractMessage)); + } + } + + internal override DataContract GetValidContract() + { + if (IsConstructorCheckRequired) + { + CheckConstructor(); + } + return this; + } + + private void CheckConstructor() + { + if (Constructor == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionTypeDoesNotHaveDefaultCtor, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + else + { + IsConstructorCheckRequired = false; + } + } + + internal override bool IsValidContract(SerializationMode mode) + { + if (mode == SerializationMode.SharedType) + { + return (SharedTypeContract != null); + } + + return (InvalidCollectionInSharedContractMessage == null); + } + + internal bool RequiresMemberAccessForRead(SecurityException securityException) + { + if (!IsTypeVisible(UnderlyingType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustCollectionContractTypeNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + if (ItemType != null && !IsTypeVisible(ItemType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustCollectionContractTypeNotPublic, + DataContract.GetClrTypeFullName(ItemType)), + securityException)); + } + return true; + } + if (ConstructorRequiresMemberAccess(Constructor)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustCollectionContractNoPublicConstructor, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + if (MethodRequiresMemberAccess(AddMethod)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustCollectionContractAddMethodNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType), + AddMethod.Name), + securityException)); + } + return true; + } + + return false; + } + + internal bool RequiresMemberAccessForWrite(SecurityException securityException) + { + if (!IsTypeVisible(UnderlyingType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustCollectionContractTypeNotPublic, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + if (ItemType != null && !IsTypeVisible(ItemType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustCollectionContractTypeNotPublic, + DataContract.GetClrTypeFullName(ItemType)), + securityException)); + } + return true; + } + + return false; + } + + internal override bool Equals(object other, Dictionary checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + { + return true; + } + + if (base.Equals(other, checkedContracts)) + { + CollectionDataContract dataContract = other as CollectionDataContract; + if (dataContract != null) + { + bool thisItemTypeIsNullable = (ItemContract == null) ? false : !ItemContract.IsValueType; + bool otherItemTypeIsNullable = (dataContract.ItemContract == null) ? false : !dataContract.ItemContract.IsValueType; + return ItemName == dataContract.ItemName && + (IsItemTypeNullable || thisItemTypeIsNullable) == (dataContract.IsItemTypeNullable || otherItemTypeIsNullable) && + ItemContract.Equals(dataContract.ItemContract, checkedContracts); + } + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + // IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset. + context.IsGetOnlyCollection = false; + XmlFormatWriterDelegate(xmlWriter, obj, context, this); + } + + public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + { + xmlReader.Read(); + object o = null; + if (context.IsGetOnlyCollection) + { + // IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset. + context.IsGetOnlyCollection = false; + XmlFormatGetOnlyCollectionReaderDelegate(xmlReader, context, CollectionItemName, Namespace, this); + } + else + { + o = XmlFormatReaderDelegate(xmlReader, context, CollectionItemName, Namespace, this); + } + xmlReader.ReadEndElement(); + return o; + } + + public class DictionaryEnumerator : IEnumerator> + { + private readonly IDictionaryEnumerator enumerator; + + public DictionaryEnumerator(IDictionaryEnumerator enumerator) + { + this.enumerator = enumerator; + } + + public void Dispose() + { + } + + public bool MoveNext() + { + return enumerator.MoveNext(); + } + + public KeyValue Current => new KeyValue(enumerator.Key, enumerator.Value); + + object System.Collections.IEnumerator.Current => Current; + + public void Reset() + { + enumerator.Reset(); + } + } + + public class GenericDictionaryEnumerator : IEnumerator> + { + private readonly IEnumerator> enumerator; + + public GenericDictionaryEnumerator(IEnumerator> enumerator) + { + this.enumerator = enumerator; + } + + public void Dispose() + { + } + + public bool MoveNext() + { + return enumerator.MoveNext(); + } + + public KeyValue Current + { + get + { + KeyValuePair current = enumerator.Current; + return new KeyValue(current.Key, current.Value); + } + } + + object System.Collections.IEnumerator.Current => Current; + + public void Reset() + { + enumerator.Reset(); + } + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataNode.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataNode.cs new file mode 100644 index 0000000..8319620 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/CollectionDataNode.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Compat.Runtime.Serialization +{ + internal class CollectionDataNode : DataNode + { + private IList items; + private string itemName; + private string itemNamespace; + private int size = -1; + + internal CollectionDataNode() + { + dataType = Globals.TypeOfCollectionDataNode; + } + + internal IList Items + { + get => items; + set => items = value; + } + + internal string ItemName + { + get => itemName; + set => itemName = value; + } + + internal string ItemNamespace + { + get => itemNamespace; + set => itemNamespace = value; + } + + internal int Size + { + get => size; + set => size = value; + } + + public override void GetData(ElementData element) + { + base.GetData(element); + + element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ArraySizeLocalName, Size.ToString(NumberFormatInfo.InvariantInfo)); + } + + public override void Clear() + { + base.Clear(); + items = null; + size = -1; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContract.cs new file mode 100644 index 0000000..87b9c5c --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContract.cs @@ -0,0 +1,2481 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Schema; +using CollectionDataContractAttribute = System.Runtime.Serialization.CollectionDataContractAttribute; +using ContractNamespaceAttribute = System.Runtime.Serialization.ContractNamespaceAttribute; +using DataContractAttribute = System.Runtime.Serialization.DataContractAttribute; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; +using KnownTypeAttribute = System.Runtime.Serialization.KnownTypeAttribute; +using SerializationException = System.Runtime.Serialization.SerializationException; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + internal abstract class DataContract + { + private readonly XmlDictionaryString _name; + + private readonly XmlDictionaryString _ns; + + private readonly DataContractCriticalHelper _helper; + + protected DataContract(DataContractCriticalHelper helper) + { + _helper = helper; + _name = helper.Name; + _ns = helper.Namespace; + } + + internal static DataContract GetDataContract(Type type) + { + return GetDataContract(type.TypeHandle, type, SerializationMode.SharedContract); + } + + internal static DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode) + { + int id = GetId(typeHandle); + return GetDataContract(id, typeHandle, mode); + } + + internal static DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle, SerializationMode mode) + { + DataContract dataContract = GetDataContractSkipValidation(id, typeHandle, null); + dataContract = dataContract.GetValidContract(mode); + + return dataContract; + } + + internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type) + { + return DataContractCriticalHelper.GetDataContractSkipValidation(id, typeHandle, type); + } + + internal static DataContract GetGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type type, SerializationMode mode) + { + DataContract dataContract = GetGetOnlyCollectionDataContractSkipValidation(id, typeHandle, type); + dataContract = dataContract.GetValidContract(mode); + if (dataContract is ClassDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.Format(SR.ClassDataContractReturnedForGetOnlyCollection, DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + return dataContract; + } + + internal static DataContract GetGetOnlyCollectionDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type) + { + return DataContractCriticalHelper.GetGetOnlyCollectionDataContractSkipValidation(id, typeHandle, type); + } + + internal static DataContract GetDataContractForInitialization(int id) + { + return DataContractCriticalHelper.GetDataContractForInitialization(id); + } + + internal static int GetIdForInitialization(ClassDataContract classContract) + { + return DataContractCriticalHelper.GetIdForInitialization(classContract); + } + + internal static int GetId(RuntimeTypeHandle typeHandle) + { + return DataContractCriticalHelper.GetId(typeHandle); + } + + public static DataContract GetBuiltInDataContract(Type type) + { + return DataContractCriticalHelper.GetBuiltInDataContract(type); + } + + public static DataContract GetBuiltInDataContract(string name, string ns) + { + return DataContractCriticalHelper.GetBuiltInDataContract(name, ns); + } + + public static DataContract GetBuiltInDataContract(string typeName) + { + return DataContractCriticalHelper.GetBuiltInDataContract(typeName); + } + + internal static string GetNamespace(string key) + { + return DataContractCriticalHelper.GetNamespace(key); + } + + internal static XmlDictionaryString GetClrTypeString(string key) + { + return DataContractCriticalHelper.GetClrTypeString(key); + } + + internal static void ThrowInvalidDataContractException(string message, Type type) + { + DataContractCriticalHelper.ThrowInvalidDataContractException(message, type); + } + + protected DataContractCriticalHelper Helper => _helper; + + internal Type UnderlyingType => _helper.UnderlyingType; + + internal Type OriginalUnderlyingType => _helper.OriginalUnderlyingType; + + + internal virtual bool IsBuiltInDataContract => _helper.IsBuiltInDataContract; + + internal Type TypeForInitialization => _helper.TypeForInitialization; + + public virtual void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + public virtual object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + internal bool IsValueType + { + get => _helper.IsValueType; + set => _helper.IsValueType = value; + } + + internal bool IsReference + { + get => _helper.IsReference; + set => _helper.IsReference = value; + } + + internal XmlQualifiedName StableName + { + get => _helper.StableName; + set => _helper.StableName = value; + } + + internal GenericInfo GenericInfo + { + get => _helper.GenericInfo; + set => _helper.GenericInfo = value; + } + + internal virtual DataContractDictionary KnownDataContracts + { + get => _helper.KnownDataContracts; + set => _helper.KnownDataContracts = value; + } + + internal virtual bool IsISerializable + { + get => _helper.IsISerializable; + set => _helper.IsISerializable = value; + } + + internal XmlDictionaryString Name => _name; + + public virtual XmlDictionaryString Namespace => _ns; + + internal virtual bool HasRoot + { + get => true; + set { } + } + + internal virtual XmlDictionaryString TopLevelElementName + { + get => _helper.TopLevelElementName; + set => _helper.TopLevelElementName = value; + } + + internal virtual XmlDictionaryString TopLevelElementNamespace + { + get => _helper.TopLevelElementNamespace; + set => _helper.TopLevelElementNamespace = value; + } + + internal virtual bool CanContainReferences => true; + + internal virtual bool IsPrimitive => false; + + internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns) + { + if (object.ReferenceEquals(ns, DictionaryGlobals.SerializationNamespace) && !IsPrimitive) + { + writer.WriteStartElement(Globals.SerPrefix, name, ns); + } + else + { + writer.WriteStartElement(name, ns); + } + } + + internal virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + return this; + } + + internal virtual DataContract GetValidContract(SerializationMode mode) + { + return this; + } + + internal virtual DataContract GetValidContract() + { + return this; + } + + internal virtual bool IsValidContract(SerializationMode mode) + { + return true; + } + + internal MethodInfo ParseMethod => _helper.ParseMethod; + + protected class DataContractCriticalHelper + { + private static readonly Dictionary typeToIDCache; + private static DataContract[] dataContractCache; + private static int dataContractID; + private static Dictionary typeToBuiltInContract; + private static Dictionary nameToBuiltInContract; + private static Dictionary typeNameToBuiltInContract; + private static Dictionary namespaces; + private static Dictionary clrTypeStrings; + private static XmlDictionary clrTypeStringsDictionary; + private static readonly TypeHandleRef typeHandleRef = new TypeHandleRef(); + private static readonly object cacheLock = new object(); + private static readonly object createDataContractLock = new object(); + private static readonly object initBuiltInContractsLock = new object(); + private static readonly object namespacesLock = new object(); + private static readonly object clrTypeStringsLock = new object(); + private readonly Type underlyingType; + private Type originalUnderlyingType; + private bool isReference; + private bool isValueType; + private XmlQualifiedName stableName; + private GenericInfo genericInfo; + private XmlDictionaryString name; + private XmlDictionaryString ns; + + private Type typeForInitialization; + private MethodInfo parseMethod; + private bool parseMethodSet; + + static DataContractCriticalHelper() + { + typeToIDCache = new Dictionary(new TypeHandleRefEqualityComparer()); + dataContractCache = new DataContract[32]; + dataContractID = 0; + } + + internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = dataContractCache[id]; + if (dataContract == null) + { + dataContract = CreateDataContract(id, typeHandle, type); + } + else + { + return dataContract.GetValidContract(); + } + return dataContract; + } + + internal static DataContract GetGetOnlyCollectionDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = dataContractCache[id]; + if (dataContract == null) + { + dataContract = CreateGetOnlyCollectionDataContract(id, typeHandle, type); + + AssignDataContractToId(dataContract, id); + } + return dataContract; + } + + internal static DataContract GetDataContractForInitialization(int id) + { + DataContract dataContract = dataContractCache[id]; + if (dataContract == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.DataContractCacheOverflow)); + } + return dataContract; + } + + internal static int GetIdForInitialization(ClassDataContract classContract) + { + int id = DataContract.GetId(classContract.TypeForInitialization.TypeHandle); + if (id < dataContractCache.Length && ContractMatches(classContract, dataContractCache[id])) + { + return id; + } + + int currentDataContractId = DataContractCriticalHelper.dataContractID; + + for (int i = 0; i < currentDataContractId; i++) + { + if (ContractMatches(classContract, dataContractCache[i])) + { + return i; + } + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.DataContractCacheOverflow)); + } + + private static bool ContractMatches(DataContract contract, DataContract cachedContract) + { + return (cachedContract != null && cachedContract.UnderlyingType == contract.UnderlyingType); + } + + internal static int GetId(RuntimeTypeHandle typeHandle) + { + lock (cacheLock) + { + typeHandle = GetDataContractAdapterTypeHandle(typeHandle); + typeHandleRef.Value = typeHandle; + if (!typeToIDCache.TryGetValue(typeHandleRef, out IntRef id)) + { + id = GetNextId(); + try + { + typeToIDCache.Add(new TypeHandleRef(typeHandle), id); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + } + } + return id.Value; + } + } + + // Assumed that this method is called under a lock + private static IntRef GetNextId() + { + int value = dataContractID++; + if (value >= dataContractCache.Length) + { + int newSize = (value < int.MaxValue / 2) ? value * 2 : int.MaxValue; + if (newSize <= value) + { + Fx.Assert("DataContract cache overflow"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.DataContractCacheOverflow)); + } + Array.Resize(ref dataContractCache, newSize); + } + return new IntRef(value); + } + + // check whether a corresponding update is required in ClassDataContract.IsNonAttributedTypeValidForSerialization + private static DataContract CreateDataContract(int id, RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = dataContractCache[id]; + + if (dataContract == null) + { + lock (createDataContractLock) + { + dataContract = dataContractCache[id]; + + if (dataContract == null) + { + if (type == null) + { + type = Type.GetTypeFromHandle(typeHandle); + } + + type = UnwrapNullableType(type); + type = GetDataContractAdapterType(type); + dataContract = GetBuiltInDataContract(type); + if (dataContract == null) + { + if (type.IsArray) + { + dataContract = new CollectionDataContract(type); + } + else if (type.IsEnum) + { + dataContract = new EnumDataContract(type); + } + else if (type.IsGenericParameter) + { + dataContract = new GenericParameterDataContract(type); + } + else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) + { + dataContract = new XmlDataContract(type); + } + else + { + //if (type.ContainsGenericParameters) + // ThrowInvalidDataContractException(SR.Format(SR.TypeMustNotBeOpenGeneric, type), type); + if (type.IsPointer) + { + type = Globals.TypeOfReflectionPointer; + } + + if (!CollectionDataContract.TryCreate(type, out dataContract)) + { + if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type)) + { + dataContract = new ClassDataContract(type); + } + else + { + ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type); + } + } + } + } + + AssignDataContractToId(dataContract, id); + } + } + } + + return dataContract; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void AssignDataContractToId(DataContract dataContract, int id) + { + lock (cacheLock) + { + dataContractCache[id] = dataContract; + } + } + + private static DataContract CreateGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = null; + lock (createDataContractLock) + { + dataContract = dataContractCache[id]; + if (dataContract == null) + { + if (type == null) + { + type = Type.GetTypeFromHandle(typeHandle); + } + + type = UnwrapNullableType(type); + type = GetDataContractAdapterType(type); + if (!CollectionDataContract.TryCreateGetOnlyCollectionDataContract(type, out dataContract)) + { + ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type); + } + } + } + return dataContract; + } + + // Any change to this method should be reflected in GetDataContractOriginalType + internal static Type GetDataContractAdapterType(Type type) + { + // Replace the DataTimeOffset ISerializable type passed in with the internal DateTimeOffsetAdapter DataContract type. + // DateTimeOffsetAdapter is used for serialization/deserialization purposes to bypass the ISerializable implementation + // on DateTimeOffset; which does not work in partial trust and to ensure correct schema import/export scenarios. + if (type == Globals.TypeOfDateTimeOffset) + { + return Globals.TypeOfDateTimeOffsetAdapter; + } + return type; + } + + // Maps adapted types back to the original type + // Any change to this method should be reflected in GetDataContractAdapterType + internal static Type GetDataContractOriginalType(Type type) + { + if (type == Globals.TypeOfDateTimeOffsetAdapter) + { + return Globals.TypeOfDateTimeOffset; + } + return type; + } + + private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHandle typeHandle) + { + if (Globals.TypeOfDateTimeOffset.TypeHandle.Equals(typeHandle)) + { + return Globals.TypeOfDateTimeOffsetAdapter.TypeHandle; + } + return typeHandle; + } + + public static DataContract GetBuiltInDataContract(Type type) + { + if (type.IsInterface && !CollectionDataContract.IsCollectionInterface(type)) + { + type = Globals.TypeOfObject; + } + + lock (initBuiltInContractsLock) + { + if (typeToBuiltInContract == null) + { + typeToBuiltInContract = new Dictionary(); + } + + if (!typeToBuiltInContract.TryGetValue(type, out DataContract dataContract)) + { + TryCreateBuiltInDataContract(type, out dataContract); + typeToBuiltInContract.Add(type, dataContract); + } + return dataContract; + } + } + + public static DataContract GetBuiltInDataContract(string name, string ns) + { + lock (initBuiltInContractsLock) + { + if (nameToBuiltInContract == null) + { + nameToBuiltInContract = new Dictionary(); + } + + XmlQualifiedName qname = new XmlQualifiedName(name, ns); + if (!nameToBuiltInContract.TryGetValue(qname, out DataContract dataContract)) + { + if (TryCreateBuiltInDataContract(name, ns, out dataContract)) + { + nameToBuiltInContract.Add(qname, dataContract); + } + } + return dataContract; + } + } + + public static DataContract GetBuiltInDataContract(string typeName) + { + if (!typeName.StartsWith("System.", StringComparison.Ordinal)) + { + return null; + } + + lock (initBuiltInContractsLock) + { + if (typeNameToBuiltInContract == null) + { + typeNameToBuiltInContract = new Dictionary(); + } + + if (!typeNameToBuiltInContract.TryGetValue(typeName, out DataContract dataContract)) + { + Type type = null; + string name = typeName.Substring(7); + if (name == "Char") + { + type = typeof(char); + } + else if (name == "Boolean") + { + type = typeof(bool); + } + else if (name == "SByte") + { + type = typeof(sbyte); + } + else if (name == "Byte") + { + type = typeof(byte); + } + else if (name == "Int16") + { + type = typeof(short); + } + else if (name == "UInt16") + { + type = typeof(ushort); + } + else if (name == "Int32") + { + type = typeof(int); + } + else if (name == "UInt32") + { + type = typeof(uint); + } + else if (name == "Int64") + { + type = typeof(long); + } + else if (name == "UInt64") + { + type = typeof(ulong); + } + else if (name == "Single") + { + type = typeof(float); + } + else if (name == "Double") + { + type = typeof(double); + } + else if (name == "Decimal") + { + type = typeof(decimal); + } + else if (name == "DateTime") + { + type = typeof(DateTime); + } + else if (name == "String") + { + type = typeof(string); + } + else if (name == "Byte[]") + { + type = typeof(byte[]); + } + else if (name == "Object") + { + type = typeof(object); + } + else if (name == "TimeSpan") + { + type = typeof(TimeSpan); + } + else if (name == "Guid") + { + type = typeof(Guid); + } + else if (name == "Uri") + { + type = typeof(Uri); + } + else if (name == "Xml.XmlQualifiedName") + { + type = typeof(XmlQualifiedName); + } + else if (name == "Enum") + { + type = typeof(Enum); + } + else if (name == "ValueType") + { + type = typeof(ValueType); + } + else if (name == "Array") + { + type = typeof(Array); + } + else if (name == "Xml.XmlElement") + { + type = typeof(XmlElement); + } + else if (name == "Xml.XmlNode[]") + { + type = typeof(XmlNode[]); + } + + if (type != null) + { + TryCreateBuiltInDataContract(type, out dataContract); + } + + typeNameToBuiltInContract.Add(typeName, dataContract); + } + return dataContract; + } + } + + public static bool TryCreateBuiltInDataContract(Type type, out DataContract dataContract) + { + if (type.IsEnum) // Type.GetTypeCode will report Enums as TypeCode.IntXX + { + dataContract = null; + return false; + } + dataContract = null; + switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + dataContract = new BooleanDataContract(); + break; + case TypeCode.Byte: + dataContract = new UnsignedByteDataContract(); + break; + case TypeCode.Char: + dataContract = new CharDataContract(); + break; + case TypeCode.DateTime: + dataContract = new DateTimeDataContract(); + break; + case TypeCode.Decimal: + dataContract = new DecimalDataContract(); + break; + case TypeCode.Double: + dataContract = new DoubleDataContract(); + break; + case TypeCode.Int16: + dataContract = new ShortDataContract(); + break; + case TypeCode.Int32: + dataContract = new IntDataContract(); + break; + case TypeCode.Int64: + dataContract = new LongDataContract(); + break; + case TypeCode.SByte: + dataContract = new SignedByteDataContract(); + break; + case TypeCode.Single: + dataContract = new FloatDataContract(); + break; + case TypeCode.String: + dataContract = new StringDataContract(); + break; + case TypeCode.UInt16: + dataContract = new UnsignedShortDataContract(); + break; + case TypeCode.UInt32: + dataContract = new UnsignedIntDataContract(); + break; + case TypeCode.UInt64: + dataContract = new UnsignedLongDataContract(); + break; + default: + if (type == typeof(byte[])) + { + dataContract = new ByteArrayDataContract(); + } + else if (type == typeof(object)) + { + dataContract = new ObjectDataContract(); + } + else if (type == typeof(Uri)) + { + dataContract = new UriDataContract(); + } + else if (type == typeof(XmlQualifiedName)) + { + dataContract = new QNameDataContract(); + } + else if (type == typeof(TimeSpan)) + { + dataContract = new TimeSpanDataContract(); + } + else if (type == typeof(Guid)) + { + dataContract = new GuidDataContract(); + } + else if (type == typeof(Enum) || type == typeof(ValueType)) + { + dataContract = new SpecialTypeDataContract(type, DictionaryGlobals.ObjectLocalName, DictionaryGlobals.SchemaNamespace); + } + else if (type == typeof(Array)) + { + dataContract = new CollectionDataContract(type); + } + else if (type == typeof(XmlElement) || type == typeof(XmlNode[])) + { + dataContract = new XmlDataContract(type); + } + + break; + } + return dataContract != null; + } + + public static bool TryCreateBuiltInDataContract(string name, string ns, out DataContract dataContract) + { + dataContract = null; + if (ns == DictionaryGlobals.SchemaNamespace.Value) + { + if (DictionaryGlobals.BooleanLocalName.Value == name) + { + dataContract = new BooleanDataContract(); + } + else if (DictionaryGlobals.SignedByteLocalName.Value == name) + { + dataContract = new SignedByteDataContract(); + } + else if (DictionaryGlobals.UnsignedByteLocalName.Value == name) + { + dataContract = new UnsignedByteDataContract(); + } + else if (DictionaryGlobals.ShortLocalName.Value == name) + { + dataContract = new ShortDataContract(); + } + else if (DictionaryGlobals.UnsignedShortLocalName.Value == name) + { + dataContract = new UnsignedShortDataContract(); + } + else if (DictionaryGlobals.IntLocalName.Value == name) + { + dataContract = new IntDataContract(); + } + else if (DictionaryGlobals.UnsignedIntLocalName.Value == name) + { + dataContract = new UnsignedIntDataContract(); + } + else if (DictionaryGlobals.LongLocalName.Value == name) + { + dataContract = new LongDataContract(); + } + else if (DictionaryGlobals.integerLocalName.Value == name) + { + dataContract = new IntegerDataContract(); + } + else if (DictionaryGlobals.positiveIntegerLocalName.Value == name) + { + dataContract = new PositiveIntegerDataContract(); + } + else if (DictionaryGlobals.negativeIntegerLocalName.Value == name) + { + dataContract = new NegativeIntegerDataContract(); + } + else if (DictionaryGlobals.nonPositiveIntegerLocalName.Value == name) + { + dataContract = new NonPositiveIntegerDataContract(); + } + else if (DictionaryGlobals.nonNegativeIntegerLocalName.Value == name) + { + dataContract = new NonNegativeIntegerDataContract(); + } + else if (DictionaryGlobals.UnsignedLongLocalName.Value == name) + { + dataContract = new UnsignedLongDataContract(); + } + else if (DictionaryGlobals.FloatLocalName.Value == name) + { + dataContract = new FloatDataContract(); + } + else if (DictionaryGlobals.DoubleLocalName.Value == name) + { + dataContract = new DoubleDataContract(); + } + else if (DictionaryGlobals.DecimalLocalName.Value == name) + { + dataContract = new DecimalDataContract(); + } + else if (DictionaryGlobals.DateTimeLocalName.Value == name) + { + dataContract = new DateTimeDataContract(); + } + else if (DictionaryGlobals.StringLocalName.Value == name) + { + dataContract = new StringDataContract(); + } + else if (DictionaryGlobals.timeLocalName.Value == name) + { + dataContract = new TimeDataContract(); + } + else if (DictionaryGlobals.dateLocalName.Value == name) + { + dataContract = new DateDataContract(); + } + else if (DictionaryGlobals.hexBinaryLocalName.Value == name) + { + dataContract = new HexBinaryDataContract(); + } + else if (DictionaryGlobals.gYearMonthLocalName.Value == name) + { + dataContract = new GYearMonthDataContract(); + } + else if (DictionaryGlobals.gYearLocalName.Value == name) + { + dataContract = new GYearDataContract(); + } + else if (DictionaryGlobals.gMonthDayLocalName.Value == name) + { + dataContract = new GMonthDayDataContract(); + } + else if (DictionaryGlobals.gDayLocalName.Value == name) + { + dataContract = new GDayDataContract(); + } + else if (DictionaryGlobals.gMonthLocalName.Value == name) + { + dataContract = new GMonthDataContract(); + } + else if (DictionaryGlobals.normalizedStringLocalName.Value == name) + { + dataContract = new NormalizedStringDataContract(); + } + else if (DictionaryGlobals.tokenLocalName.Value == name) + { + dataContract = new TokenDataContract(); + } + else if (DictionaryGlobals.languageLocalName.Value == name) + { + dataContract = new LanguageDataContract(); + } + else if (DictionaryGlobals.NameLocalName.Value == name) + { + dataContract = new NameDataContract(); + } + else if (DictionaryGlobals.NCNameLocalName.Value == name) + { + dataContract = new NCNameDataContract(); + } + else if (DictionaryGlobals.XSDIDLocalName.Value == name) + { + dataContract = new IDDataContract(); + } + else if (DictionaryGlobals.IDREFLocalName.Value == name) + { + dataContract = new IDREFDataContract(); + } + else if (DictionaryGlobals.IDREFSLocalName.Value == name) + { + dataContract = new IDREFSDataContract(); + } + else if (DictionaryGlobals.ENTITYLocalName.Value == name) + { + dataContract = new ENTITYDataContract(); + } + else if (DictionaryGlobals.ENTITIESLocalName.Value == name) + { + dataContract = new ENTITIESDataContract(); + } + else if (DictionaryGlobals.NMTOKENLocalName.Value == name) + { + dataContract = new NMTOKENDataContract(); + } + else if (DictionaryGlobals.NMTOKENSLocalName.Value == name) + { + dataContract = new NMTOKENDataContract(); + } + else if (DictionaryGlobals.ByteArrayLocalName.Value == name) + { + dataContract = new ByteArrayDataContract(); + } + else if (DictionaryGlobals.ObjectLocalName.Value == name) + { + dataContract = new ObjectDataContract(); + } + else if (DictionaryGlobals.TimeSpanLocalName.Value == name) + { + dataContract = new XsDurationDataContract(); + } + else if (DictionaryGlobals.UriLocalName.Value == name) + { + dataContract = new UriDataContract(); + } + else if (DictionaryGlobals.QNameLocalName.Value == name) + { + dataContract = new QNameDataContract(); + } + } + else if (ns == DictionaryGlobals.SerializationNamespace.Value) + { + if (DictionaryGlobals.TimeSpanLocalName.Value == name) + { + dataContract = new TimeSpanDataContract(); + } + else if (DictionaryGlobals.GuidLocalName.Value == name) + { + dataContract = new GuidDataContract(); + } + else if (DictionaryGlobals.CharLocalName.Value == name) + { + dataContract = new CharDataContract(); + } + else if ("ArrayOfanyType" == name) + { + dataContract = new CollectionDataContract(typeof(Array)); + } + } + else if (ns == DictionaryGlobals.AsmxTypesNamespace.Value) + { + if (DictionaryGlobals.CharLocalName.Value == name) + { + dataContract = new AsmxCharDataContract(); + } + else if (DictionaryGlobals.GuidLocalName.Value == name) + { + dataContract = new AsmxGuidDataContract(); + } + } + else if (ns == Globals.DataContractXmlNamespace) + { + if (name == "XmlElement") + { + dataContract = new XmlDataContract(typeof(XmlElement)); + } + else if (name == "ArrayOfXmlNode") + { + dataContract = new XmlDataContract(typeof(XmlNode[])); + } + } + return dataContract != null; + } + + internal static string GetNamespace(string key) + { + lock (namespacesLock) + { + if (namespaces == null) + { + namespaces = new Dictionary(); + } + + if (namespaces.TryGetValue(key, out string value)) + { + return value; + } + + try + { + namespaces.Add(key, key); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + } + return key; + } + } + + internal static XmlDictionaryString GetClrTypeString(string key) + { + lock (clrTypeStringsLock) + { + if (clrTypeStrings == null) + { + clrTypeStringsDictionary = new XmlDictionary(); + clrTypeStrings = new Dictionary(); + try + { + clrTypeStrings.Add(Globals.TypeOfInt.Assembly.FullName, clrTypeStringsDictionary.Add(Globals.MscorlibAssemblyName)); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + } + } + if (clrTypeStrings.TryGetValue(key, out XmlDictionaryString value)) + { + return value; + } + + value = clrTypeStringsDictionary.Add(key); + try + { + clrTypeStrings.Add(key, value); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + } + return value; + } + } + + internal static void ThrowInvalidDataContractException(string message, Type type) + { + if (type != null) + { + lock (cacheLock) + { + typeHandleRef.Value = GetDataContractAdapterTypeHandle(type.TypeHandle); + try + { + typeToIDCache.Remove(typeHandleRef); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + } + } + } + + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(message)); + } + + internal DataContractCriticalHelper() + { + } + + internal DataContractCriticalHelper(Type type) + { + underlyingType = type; + SetTypeForInitialization(type); + isValueType = type.IsValueType; + } + + internal Type UnderlyingType => underlyingType; + + internal Type OriginalUnderlyingType + { + get + { + if (originalUnderlyingType == null) + { + originalUnderlyingType = GetDataContractOriginalType(underlyingType); + } + return originalUnderlyingType; + } + } + + internal virtual bool IsBuiltInDataContract => false; + + internal Type TypeForInitialization => typeForInitialization; + + private void SetTypeForInitialization(Type classType) + { + if (classType.IsSerializable || classType.IsDefined(Globals.TypeOfDataContractAttribute, false)) + { + typeForInitialization = classType; + } + } + + internal bool IsReference + { + get => isReference; + set => isReference = value; + } + + internal bool IsValueType + { + get => isValueType; + set => isValueType = value; + } + + internal XmlQualifiedName StableName + { + get => stableName; + set => stableName = value; + } + + internal GenericInfo GenericInfo + { + get => genericInfo; + set => genericInfo = value; + } + + internal virtual DataContractDictionary KnownDataContracts + { + get => null; + set { /* do nothing */ } + } + + internal virtual bool IsISerializable + { + get => false; + set => ThrowInvalidDataContractException(SR.RequiresClassDataContractToSetIsISerializable); + } + + internal XmlDictionaryString Name + { + get => name; + set => name = value; + } + + public XmlDictionaryString Namespace + { + get => ns; + set => ns = value; + } + + internal virtual bool HasRoot + { + get => true; + set { } + } + + internal virtual XmlDictionaryString TopLevelElementName + { + get => name; + set => name = value; + } + + internal virtual XmlDictionaryString TopLevelElementNamespace + { + get => ns; + set => ns = value; + } + + internal virtual bool CanContainReferences => true; + + internal virtual bool IsPrimitive => false; + + internal MethodInfo ParseMethod + { + get + { + if (!parseMethodSet) + { + MethodInfo method = UnderlyingType.GetMethod(Globals.ParseMethodName, BindingFlags.Public | BindingFlags.Static, null, new Type[] { Globals.TypeOfString }, null); + + if (method != null && method.ReturnType == UnderlyingType) + { + parseMethod = method; + } + + parseMethodSet = true; + } + return parseMethod; + } + } + + internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns) + { + if (object.ReferenceEquals(ns, DictionaryGlobals.SerializationNamespace) && !IsPrimitive) + { + writer.WriteStartElement(Globals.SerPrefix, name, ns); + } + else + { + writer.WriteStartElement(name, ns); + } + } + + internal void SetDataContractName(XmlQualifiedName stableName) + { + XmlDictionary dictionary = new XmlDictionary(2); + Name = dictionary.Add(stableName.Name); + Namespace = dictionary.Add(stableName.Namespace); + StableName = stableName; + } + + internal void SetDataContractName(XmlDictionaryString name, XmlDictionaryString ns) + { + Name = name; + Namespace = ns; + StableName = CreateQualifiedName(name.Value, ns.Value); + } + + internal void ThrowInvalidDataContractException(string message) + { + ThrowInvalidDataContractException(message, UnderlyingType); + } + } + + internal static bool IsTypeSerializable(Type type) + { + return IsTypeSerializable(type, new Dictionary()); + } + + private static bool IsTypeSerializable(Type type, Dictionary previousCollectionTypes) + { + if (type.IsSerializable || + type.IsDefined(Globals.TypeOfDataContractAttribute, false) || + type.IsInterface || + type.IsPointer || + Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) + { + return true; + } + if (CollectionDataContract.IsCollection(type, out Type itemType)) + { + ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); + if (IsTypeSerializable(itemType, previousCollectionTypes)) + { + return true; + } + } + return (DataContract.GetBuiltInDataContract(type) != null || ClassDataContract.IsNonAttributedTypeValidForSerialization(type)); + } + + private static void ValidatePreviousCollectionTypes(Type collectionType, Type itemType, Dictionary previousCollectionTypes) + { + previousCollectionTypes.Add(collectionType, collectionType); + while (itemType.IsArray) + { + itemType = itemType.GetElementType(); + } + + // Do a breadth first traversal of the generic type tree to + // produce the closure of all generic argument types and + // check that none of these is in the previousCollectionTypes + + List itemTypeClosure = new List(); + Queue itemTypeQueue = new Queue(); + + itemTypeQueue.Enqueue(itemType); + itemTypeClosure.Add(itemType); + + while (itemTypeQueue.Count > 0) + { + itemType = itemTypeQueue.Dequeue(); + if (previousCollectionTypes.ContainsKey(itemType)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.RecursiveCollectionType, DataContract.GetClrTypeFullName(itemType)))); + } + if (itemType.IsGenericType) + { + foreach (Type argType in itemType.GetGenericArguments()) + { + if (!itemTypeClosure.Contains(argType)) + { + itemTypeQueue.Enqueue(argType); + itemTypeClosure.Add(argType); + } + } + } + } + } + + internal static Type UnwrapRedundantNullableType(Type type) + { + Type nullableType = type; + while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable) + { + nullableType = type; + type = type.GetGenericArguments()[0]; + } + return nullableType; + } + + internal static Type UnwrapNullableType(Type type) + { + while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable) + { + type = type.GetGenericArguments()[0]; + } + + return type; + } + + private static bool IsAlpha(char ch) + { + return (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z'); + } + + private static bool IsDigit(char ch) + { + return (ch >= '0' && ch <= '9'); + } + + private static bool IsAsciiLocalName(string localName) + { + if (localName.Length == 0) + { + return false; + } + + if (!IsAlpha(localName[0])) + { + return false; + } + + for (int i = 1; i < localName.Length; i++) + { + char ch = localName[i]; + if (!IsAlpha(ch) && !IsDigit(ch)) + { + return false; + } + } + return true; + } + + internal static string EncodeLocalName(string localName) + { + if (IsAsciiLocalName(localName)) + { + return localName; + } + + if (IsValidNCName(localName)) + { + return localName; + } + + return XmlConvert.EncodeLocalName(localName); + } + + internal static bool IsValidNCName(string name) + { + try + { + XmlConvert.VerifyNCName(name); + return true; + } + catch (XmlException) + { + return false; + } + } + + internal static XmlQualifiedName GetStableName(Type type) + { + return GetStableName(type, out bool hasDataContract); + } + + internal static XmlQualifiedName GetStableName(Type type, out bool hasDataContract) + { + return GetStableName(type, new Dictionary(), out hasDataContract); + } + + private static XmlQualifiedName GetStableName(Type type, Dictionary previousCollectionTypes, out bool hasDataContract) + { + type = UnwrapRedundantNullableType(type); + if (TryGetBuiltInXmlAndArrayTypeStableName(type, previousCollectionTypes, out XmlQualifiedName stableName)) + { + hasDataContract = false; + } + else + { + if (TryGetDCAttribute(type, out DataContractAttribute dataContractAttribute)) + { + stableName = GetDCTypeStableName(type, dataContractAttribute); + hasDataContract = true; + } + else + { + stableName = GetNonDCTypeStableName(type, previousCollectionTypes); + hasDataContract = false; + } + } + + return stableName; + } + + private static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttribute dataContractAttribute) + { + string name = null, ns = null; + if (dataContractAttribute.IsNameSetExplicitly) + { + name = dataContractAttribute.Name; + if (name == null || name.Length == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidDataContractName, DataContract.GetClrTypeFullName(type)))); + } + + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + name = ExpandGenericParameters(name, type); + } + + name = DataContract.EncodeLocalName(name); + } + else + { + name = GetDefaultStableLocalName(type); + } + + if (dataContractAttribute.IsNamespaceSetExplicitly) + { + ns = dataContractAttribute.Namespace; + if (ns == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidDataContractNamespace, DataContract.GetClrTypeFullName(type)))); + } + + CheckExplicitDataContractNamespaceUri(ns, type); + } + else + { + ns = GetDefaultDataContractNamespace(type); + } + + return CreateQualifiedName(name, ns); + } + + private static XmlQualifiedName GetNonDCTypeStableName(Type type, Dictionary previousCollectionTypes) + { + string name = null, ns = null; + + if (CollectionDataContract.IsCollection(type, out Type itemType)) + { + ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); + return GetCollectionStableName(type, itemType, previousCollectionTypes, out CollectionDataContractAttribute collectionContractAttribute); + } + name = GetDefaultStableLocalName(type); + + // ensures that ContractNamespaceAttribute is honored when used with non-attributed types + if (ClassDataContract.IsNonAttributedTypeValidForSerialization(type)) + { + ns = GetDefaultDataContractNamespace(type); + } + else + { + ns = GetDefaultStableNamespace(type); + } + return CreateQualifiedName(name, ns); + } + + private static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, Dictionary previousCollectionTypes, out XmlQualifiedName stableName) + { + stableName = null; + + DataContract builtInContract = GetBuiltInDataContract(type); + if (builtInContract != null) + { + stableName = builtInContract.StableName; + } + else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) + { + SchemaExporter.GetXmlTypeInfo(type, out XmlQualifiedName xmlTypeStableName, out XmlSchemaType xsdType, out bool hasRoot); + stableName = xmlTypeStableName; + } + else if (type.IsArray) + { + Type itemType = type.GetElementType(); + ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); + stableName = GetCollectionStableName(type, itemType, previousCollectionTypes, out CollectionDataContractAttribute collectionContractAttribute); + } + return stableName != null; + } + + internal static bool TryGetDCAttribute(Type type, out DataContractAttribute dataContractAttribute) + { + dataContractAttribute = null; + + object[] dataContractAttributes = type.GetCustomAttributes(Globals.TypeOfDataContractAttribute, false); + if (dataContractAttributes != null && dataContractAttributes.Length > 0) + { +#if DEBUG + if (dataContractAttributes.Length > 1) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TooManyDataContracts, DataContract.GetClrTypeFullName(type)))); + } +#endif + dataContractAttribute = (DataContractAttribute)dataContractAttributes[0]; + } + + return dataContractAttribute != null; + } + + internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, out CollectionDataContractAttribute collectionContractAttribute) + { + return GetCollectionStableName(type, itemType, new Dictionary(), out collectionContractAttribute); + } + + private static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, Dictionary previousCollectionTypes, out CollectionDataContractAttribute collectionContractAttribute) + { + string name, ns; + object[] collectionContractAttributes = type.GetCustomAttributes(Globals.TypeOfCollectionDataContractAttribute, false); + if (collectionContractAttributes != null && collectionContractAttributes.Length > 0) + { +#if DEBUG + if (collectionContractAttributes.Length > 1) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TooManyCollectionContracts, DataContract.GetClrTypeFullName(type)))); + } +#endif + collectionContractAttribute = (CollectionDataContractAttribute)collectionContractAttributes[0]; + if (collectionContractAttribute.IsNameSetExplicitly) + { + name = collectionContractAttribute.Name; + if (name == null || name.Length == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractName, DataContract.GetClrTypeFullName(type)))); + } + + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + name = ExpandGenericParameters(name, type); + } + + name = DataContract.EncodeLocalName(name); + } + else + { + name = GetDefaultStableLocalName(type); + } + + if (collectionContractAttribute.IsNamespaceSetExplicitly) + { + ns = collectionContractAttribute.Namespace; + if (ns == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidCollectionContractNamespace, DataContract.GetClrTypeFullName(type)))); + } + + CheckExplicitDataContractNamespaceUri(ns, type); + } + else + { + ns = GetDefaultDataContractNamespace(type); + } + } + else + { + collectionContractAttribute = null; + string arrayOfPrefix = Globals.ArrayPrefix + GetArrayPrefix(ref itemType); + XmlQualifiedName elementStableName = GetStableName(itemType, previousCollectionTypes, out bool hasDataContract); + name = arrayOfPrefix + elementStableName.Name; + ns = GetCollectionNamespace(elementStableName.Namespace); + } + return CreateQualifiedName(name, ns); + } + + private static string GetArrayPrefix(ref Type itemType) + { + string arrayOfPrefix = string.Empty; + while (itemType.IsArray) + { + if (DataContract.GetBuiltInDataContract(itemType) != null) + { + break; + } + + arrayOfPrefix += Globals.ArrayPrefix; + itemType = itemType.GetElementType(); + } + return arrayOfPrefix; + } + + internal XmlQualifiedName GetArrayTypeName(bool isNullable) + { + XmlQualifiedName itemName; + if (IsValueType && isNullable) + { + GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName); + genericInfo.Add(new GenericInfo(StableName, null)); + genericInfo.AddToLevel(0, 1); + itemName = genericInfo.GetExpandedStableName(); + } + else + { + itemName = StableName; + } + + string ns = GetCollectionNamespace(itemName.Namespace); + string name = Globals.ArrayPrefix + itemName.Name; + return new XmlQualifiedName(name, ns); + } + + internal static string GetCollectionNamespace(string elementNs) + { + return IsBuiltInNamespace(elementNs) ? Globals.CollectionsNamespace : elementNs; + } + + internal static XmlQualifiedName GetDefaultStableName(Type type) + { + return CreateQualifiedName(GetDefaultStableLocalName(type), GetDefaultStableNamespace(type)); + } + + private static string GetDefaultStableLocalName(Type type) + { + if (type.IsGenericParameter) + { + return "{" + type.GenericParameterPosition + "}"; + } + + string typeName; + string arrayPrefix = null; + if (type.IsArray) + { + arrayPrefix = GetArrayPrefix(ref type); + } + + if (type.DeclaringType == null) + { + typeName = type.Name; + } + else + { + int nsLen = (type.Namespace == null) ? 0 : type.Namespace.Length; + if (nsLen > 0) + { + nsLen++; //include the . following namespace + } + + typeName = DataContract.GetClrTypeFullName(type).Substring(nsLen).Replace('+', '.'); + } + if (arrayPrefix != null) + { + typeName = arrayPrefix + typeName; + } + + if (type.IsGenericType) + { + StringBuilder localName = new StringBuilder(); + StringBuilder namespaces = new StringBuilder(); + bool parametersFromBuiltInNamespaces = true; + int iParam = typeName.IndexOf('['); + if (iParam >= 0) + { + typeName = typeName.Substring(0, iParam); + } + + IList nestedParamCounts = GetDataContractNameForGenericName(typeName, localName); + bool isTypeOpenGeneric = type.IsGenericTypeDefinition; + Type[] genParams = type.GetGenericArguments(); + for (int i = 0; i < genParams.Length; i++) + { + Type genParam = genParams[i]; + if (isTypeOpenGeneric) + { + localName.Append("{").Append(i).Append("}"); + } + else + { + XmlQualifiedName qname = DataContract.GetStableName(genParam); + localName.Append(qname.Name); + namespaces.Append(" ").Append(qname.Namespace); + if (parametersFromBuiltInNamespaces) + { + parametersFromBuiltInNamespaces = IsBuiltInNamespace(qname.Namespace); + } + } + } + if (isTypeOpenGeneric) + { + localName.Append("{#}"); + } + else if (nestedParamCounts.Count > 1 || !parametersFromBuiltInNamespaces) + { + foreach (int count in nestedParamCounts) + { + namespaces.Insert(0, count).Insert(0, " "); + } + + localName.Append(GetNamespacesDigest(namespaces.ToString())); + } + typeName = localName.ToString(); + } + return DataContract.EncodeLocalName(typeName); + } + + private static string GetDefaultDataContractNamespace(Type type) + { + string clrNs = type.Namespace; + if (clrNs == null) + { + clrNs = string.Empty; + } + + string ns = GetGlobalDataContractNamespace(clrNs, type.Module); + if (ns == null) + { + ns = GetGlobalDataContractNamespace(clrNs, type.Assembly); + } + + if (ns == null) + { + ns = GetDefaultStableNamespace(type); + } + else + { + CheckExplicitDataContractNamespaceUri(ns, type); + } + + return ns; + } + + internal static IList GetDataContractNameForGenericName(string typeName, StringBuilder localName) + { + List nestedParamCounts = new List(); + for (int startIndex = 0, endIndex; ;) + { + endIndex = typeName.IndexOf('`', startIndex); + if (endIndex < 0) + { + if (localName != null) + { + localName.Append(typeName.Substring(startIndex)); + } + + nestedParamCounts.Add(0); + break; + } + if (localName != null) + { + localName.Append(typeName.Substring(startIndex, endIndex - startIndex)); + } + + while ((startIndex = typeName.IndexOf('.', startIndex + 1, endIndex - startIndex - 1)) >= 0) + { + nestedParamCounts.Add(0); + } + + startIndex = typeName.IndexOf('.', endIndex); + if (startIndex < 0) + { + nestedParamCounts.Add(int.Parse(typeName.Substring(endIndex + 1), CultureInfo.InvariantCulture)); + break; + } + else + { + nestedParamCounts.Add(int.Parse(typeName.Substring(endIndex + 1, startIndex - endIndex - 1), CultureInfo.InvariantCulture)); + } + } + if (localName != null) + { + localName.Append("Of"); + } + + return nestedParamCounts; + } + + internal static bool IsBuiltInNamespace(string ns) + { + return (ns == Globals.SchemaNamespace || ns == Globals.SerializationNamespace); + } + + internal static string GetDefaultStableNamespace(Type type) + { + if (type.IsGenericParameter) + { + return "{ns}"; + } + + return GetDefaultStableNamespace(type.Namespace); + } + + internal static XmlQualifiedName CreateQualifiedName(string localName, string ns) + { + return new XmlQualifiedName(localName, GetNamespace(ns)); + } + + internal static string GetDefaultStableNamespace(string clrNs) + { + if (clrNs == null) + { + clrNs = string.Empty; + } + + return new Uri(Globals.DataContractXsdBaseNamespaceUri, clrNs).AbsoluteUri; + } + + private static void CheckExplicitDataContractNamespaceUri(string dataContractNs, Type type) + { + if (dataContractNs.Length > 0) + { + string trimmedNs = dataContractNs.Trim(); + // Code similar to XmlConvert.ToUri (string.Empty is a valid uri but not " ") + if (trimmedNs.Length == 0 || trimmedNs.IndexOf("##", StringComparison.Ordinal) != -1) + { + ThrowInvalidDataContractException(SR.Format(SR.DataContractNamespaceIsNotValid, dataContractNs), type); + } + + dataContractNs = trimmedNs; + } + if (Uri.TryCreate(dataContractNs, UriKind.RelativeOrAbsolute, out Uri uri)) + { + if (uri.ToString() == Globals.SerializationNamespace) + { + ThrowInvalidDataContractException(SR.Format(SR.DataContractNamespaceReserved, Globals.SerializationNamespace), type); + } + } + else + { + ThrowInvalidDataContractException(SR.Format(SR.DataContractNamespaceIsNotValid, dataContractNs), type); + } + } + + internal static string GetClrTypeFullName(Type type) + { + return !type.IsGenericTypeDefinition && type.ContainsGenericParameters ? string.Format(CultureInfo.InvariantCulture, "{0}.{1}", type.Namespace, type.Name) : type.FullName; + } + + internal static string GetClrAssemblyName(Type type, out bool hasTypeForwardedFrom) + { + hasTypeForwardedFrom = false; + object[] typeAttributes = type.GetCustomAttributes(typeof(TypeForwardedFromAttribute), false); + if (typeAttributes != null && typeAttributes.Length > 0) + { + TypeForwardedFromAttribute typeForwardedFromAttribute = (TypeForwardedFromAttribute)typeAttributes[0]; + hasTypeForwardedFrom = true; + return typeForwardedFromAttribute.AssemblyFullName; + } + else + { + return type.Assembly.FullName; + } + } + + internal static string GetClrTypeFullNameUsingTypeForwardedFromAttribute(Type type) + { + if (type.IsArray) + { + return GetClrTypeFullNameForArray(type); + } + else + { + return GetClrTypeFullNameForNonArrayTypes(type); + } + } + + private static string GetClrTypeFullNameForArray(Type type) + { + return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", + GetClrTypeFullNameUsingTypeForwardedFromAttribute(type.GetElementType()), Globals.OpenBracket, Globals.CloseBracket); + } + + private static string GetClrTypeFullNameForNonArrayTypes(Type type) + { + if (!type.IsGenericType) + { + return DataContract.GetClrTypeFullName(type); + } + + Type[] genericArguments = type.GetGenericArguments(); + StringBuilder builder = new StringBuilder(type.GetGenericTypeDefinition().FullName).Append(Globals.OpenBracket); + + foreach (Type genericArgument in genericArguments) + { + builder.Append(Globals.OpenBracket).Append(GetClrTypeFullNameUsingTypeForwardedFromAttribute(genericArgument)).Append(Globals.Comma); + builder.Append(Globals.Space).Append(GetClrAssemblyName(genericArgument, out bool hasTypeForwardedFrom)); + builder.Append(Globals.CloseBracket).Append(Globals.Comma); + } + + //remove the last comma and close typename for generic with a close bracket + return builder.Remove(builder.Length - 1, 1).Append(Globals.CloseBracket).ToString(); + } + + internal static void GetClrNameAndNamespace(string fullTypeName, out string localName, out string ns) + { + int nsEnd = fullTypeName.LastIndexOf('.'); + if (nsEnd < 0) + { + ns = string.Empty; + localName = fullTypeName.Replace('+', '.'); + } + else + { + ns = fullTypeName.Substring(0, nsEnd); + localName = fullTypeName.Substring(nsEnd + 1).Replace('+', '.'); + } + int iParam = localName.IndexOf('['); + if (iParam >= 0) + { + localName = localName.Substring(0, iParam); + } + } + + internal static void GetDefaultStableName(string fullTypeName, out string localName, out string ns) + { + CodeTypeReference typeReference = new CodeTypeReference(fullTypeName); + GetDefaultStableName(typeReference, out localName, out ns); + } + + private static void GetDefaultStableName(CodeTypeReference typeReference, out string localName, out string ns) + { + string fullTypeName = typeReference.BaseType; + DataContract dataContract = GetBuiltInDataContract(fullTypeName); + if (dataContract != null) + { + localName = dataContract.StableName.Name; + ns = dataContract.StableName.Namespace; + return; + } + GetClrNameAndNamespace(fullTypeName, out localName, out ns); + if (typeReference.TypeArguments.Count > 0) + { + StringBuilder localNameBuilder = new StringBuilder(); + StringBuilder argNamespacesBuilder = new StringBuilder(); + bool parametersFromBuiltInNamespaces = true; + IList nestedParamCounts = GetDataContractNameForGenericName(localName, localNameBuilder); + foreach (CodeTypeReference typeArg in typeReference.TypeArguments) + { + GetDefaultStableName(typeArg, out string typeArgName, out string typeArgNs); + localNameBuilder.Append(typeArgName); + argNamespacesBuilder.Append(" ").Append(typeArgNs); + if (parametersFromBuiltInNamespaces) + { + parametersFromBuiltInNamespaces = IsBuiltInNamespace(typeArgNs); + } + } + if (nestedParamCounts.Count > 1 || !parametersFromBuiltInNamespaces) + { + foreach (int count in nestedParamCounts) + { + argNamespacesBuilder.Insert(0, count).Insert(0, " "); + } + + localNameBuilder.Append(GetNamespacesDigest(argNamespacesBuilder.ToString())); + } + localName = localNameBuilder.ToString(); + } + localName = DataContract.EncodeLocalName(localName); + ns = GetDefaultStableNamespace(ns); + } + + internal static string GetDataContractNamespaceFromUri(string uriString) + { + return uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal) ? uriString.Substring(Globals.DataContractXsdBaseNamespace.Length) : uriString; + } + + private static string GetGlobalDataContractNamespace(string clrNs, ICustomAttributeProvider customAttribuetProvider) + { + object[] nsAttributes = customAttribuetProvider.GetCustomAttributes(typeof(ContractNamespaceAttribute), false); + string dataContractNs = null; + for (int i = 0; i < nsAttributes.Length; i++) + { + ContractNamespaceAttribute nsAttribute = (ContractNamespaceAttribute)nsAttributes[i]; + string clrNsInAttribute = nsAttribute.ClrNamespace; + if (clrNsInAttribute == null) + { + clrNsInAttribute = string.Empty; + } + + if (clrNsInAttribute == clrNs) + { + if (nsAttribute.ContractNamespace == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidGlobalDataContractNamespace, clrNs))); + } + + if (dataContractNs != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.DataContractNamespaceAlreadySet, dataContractNs, nsAttribute.ContractNamespace, clrNs))); + } + + dataContractNs = nsAttribute.ContractNamespace; + } + } + return dataContractNs; + } + + private static string GetNamespacesDigest(string namespaces) + { + byte[] namespaceBytes = Encoding.UTF8.GetBytes(namespaces); + byte[] digestBytes = HashHelper.ComputeHash(namespaceBytes); + char[] digestChars = new char[24]; + const int digestLen = 6; + int digestCharsLen = Convert.ToBase64CharArray(digestBytes, 0, digestLen, digestChars, 0); + StringBuilder digest = new StringBuilder(); + for (int i = 0; i < digestCharsLen; i++) + { + char ch = digestChars[i]; + switch (ch) + { + case '=': + break; + case '/': + digest.Append("_S"); + break; + case '+': + digest.Append("_P"); + break; + default: + digest.Append(ch); + break; + } + } + return digest.ToString(); + } + + private static string ExpandGenericParameters(string format, Type type) + { + GenericNameProvider genericNameProviderForType = new GenericNameProvider(type); + return ExpandGenericParameters(format, genericNameProviderForType); + } + + internal static string ExpandGenericParameters(string format, IGenericNameProvider genericNameProvider) + { + string digest = null; + StringBuilder typeName = new StringBuilder(); + IList nestedParameterCounts = genericNameProvider.GetNestedParameterCounts(); + for (int i = 0; i < format.Length; i++) + { + char ch = format[i]; + if (ch == '{') + { + i++; + int start = i; + for (; i < format.Length; i++) + { + if (format[i] == '}') + { + break; + } + } + + if (i == format.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericNameBraceMismatch, format, genericNameProvider.GetGenericTypeName()))); + } + + if (format[start] == '#' && i == (start + 1)) + { + if (nestedParameterCounts.Count > 1 || !genericNameProvider.ParametersFromBuiltInNamespaces) + { + if (digest == null) + { + StringBuilder namespaces = new StringBuilder(genericNameProvider.GetNamespaces()); + foreach (int count in nestedParameterCounts) + { + namespaces.Insert(0, count).Insert(0, " "); + } + + digest = GetNamespacesDigest(namespaces.ToString()); + } + typeName.Append(digest); + } + } + else + { + if (!int.TryParse(format.Substring(start, i - start), out int paramIndex) || paramIndex < 0 || paramIndex >= genericNameProvider.GetParameterCount()) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericParameterNotValid, format.Substring(start, i - start), genericNameProvider.GetGenericTypeName(), genericNameProvider.GetParameterCount() - 1))); + } + + typeName.Append(genericNameProvider.GetParameterName(paramIndex)); + } + } + else + { + typeName.Append(ch); + } + } + return typeName.ToString(); + } + + internal static bool IsTypeNullable(Type type) + { + return !type.IsValueType || + (type.IsGenericType && + type.GetGenericTypeDefinition() == Globals.TypeOfNullable); + } + + public static void ThrowTypeNotSerializable(Type type) + { + ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type); + } + + internal static DataContractDictionary ImportKnownTypeAttributes(Type type) + { + DataContractDictionary knownDataContracts = null; + Dictionary typesChecked = new Dictionary(); + ImportKnownTypeAttributes(type, typesChecked, ref knownDataContracts); + return knownDataContracts; + } + + private static void ImportKnownTypeAttributes(Type type, Dictionary typesChecked, ref DataContractDictionary knownDataContracts) + { + while (type != null && DataContract.IsTypeSerializable(type)) + { + if (typesChecked.ContainsKey(type)) + { + return; + } + + typesChecked.Add(type, type); + object[] knownTypeAttributes = type.GetCustomAttributes(Globals.TypeOfKnownTypeAttribute, false); + if (knownTypeAttributes != null) + { + KnownTypeAttribute kt; + bool useMethod = false, useType = false; + for (int i = 0; i < knownTypeAttributes.Length; ++i) + { + kt = (KnownTypeAttribute)knownTypeAttributes[i]; + if (kt.Type != null) + { + if (useMethod) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeOneScheme, DataContract.GetClrTypeFullName(type)), type); + } + + CheckAndAdd(kt.Type, typesChecked, ref knownDataContracts); + useType = true; + } + else + { + if (useMethod || useType) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeOneScheme, DataContract.GetClrTypeFullName(type)), type); + } + + string methodName = kt.MethodName; + if (methodName == null) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeNoData, DataContract.GetClrTypeFullName(type)), type); + } + + if (methodName.Length == 0) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeEmptyString, DataContract.GetClrTypeFullName(type)), type); + } + + MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + if (method == null) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeUnknownMethod, methodName, DataContract.GetClrTypeFullName(type)), type); + } + + if (!Globals.TypeOfTypeEnumerable.IsAssignableFrom(method.ReturnType)) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeReturnType, DataContract.GetClrTypeFullName(type), methodName), type); + } + + object types = method.Invoke(null, Globals.EmptyObjectArray); + if (types == null) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeMethodNull, DataContract.GetClrTypeFullName(type)), type); + } + + foreach (Type ty in (IEnumerable)types) + { + if (ty == null) + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeValidMethodTypes, DataContract.GetClrTypeFullName(type)), type); + } + + CheckAndAdd(ty, typesChecked, ref knownDataContracts); + } + + useMethod = true; + } + } + } + + type = type.BaseType; + } + } + + + private static void CheckRootTypeInConfigIsGeneric(Type type, ref Type rootType, ref Type[] genArgs) + { + if (rootType.IsGenericType) + { + if (!rootType.ContainsGenericParameters) + { + genArgs = rootType.GetGenericArguments(); + rootType = rootType.GetGenericTypeDefinition(); + } + else + { + DataContract.ThrowInvalidDataContractException(SR.Format(SR.TypeMustBeConcrete, type), type); + } + } + } + + private static bool IsElemTypeNullOrNotEqualToRootType(string elemTypeName, Type rootType) + { + Type t = Type.GetType(elemTypeName, false); + if (t == null || !rootType.Equals(t)) + { + return true; + } + return false; + } + + private static bool IsCollectionElementTypeEqualToRootType(string collectionElementTypeName, Type rootType) + { + if (collectionElementTypeName.StartsWith(DataContract.GetClrTypeFullName(rootType), StringComparison.Ordinal)) + { + Type t = Type.GetType(collectionElementTypeName, false); + if (t != null) + { + if (t.IsGenericType && !IsOpenGenericType(t)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.KnownTypeConfigClosedGenericDeclared, collectionElementTypeName))); + } + else if (rootType.Equals(t)) + { + return true; + } + } + } + return false; + } + + internal static void CheckAndAdd(Type type, Dictionary typesChecked, ref DataContractDictionary nameToDataContractTable) + { + type = DataContract.UnwrapNullableType(type); + DataContract dataContract = DataContract.GetDataContract(type); + if (nameToDataContractTable == null) + { + nameToDataContractTable = new DataContractDictionary(); + } + else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out DataContract alreadyExistingContract)) + { + if (alreadyExistingContract.UnderlyingType != DataContractCriticalHelper.GetDataContractAdapterType(type)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInKnownTypes, type, alreadyExistingContract.UnderlyingType, dataContract.StableName.Namespace, dataContract.StableName.Name))); + } + + return; + } + nameToDataContractTable.Add(dataContract.StableName, dataContract); + ImportKnownTypeAttributes(type, typesChecked, ref nameToDataContractTable); + } + + private static bool IsOpenGenericType(Type t) + { + Type[] args = t.GetGenericArguments(); + for (int i = 0; i < args.Length; ++i) + { + if (!args[i].IsGenericParameter) + { + return false; + } + } + + return true; + } + + public sealed override bool Equals(object other) + { + if ((object)this == other) + { + return true; + } + + return Equals(other, new Dictionary()); + } + + internal virtual bool Equals(object other, Dictionary checkedContracts) + { + DataContract dataContract = other as DataContract; + if (dataContract != null) + { + return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace && IsReference == dataContract.IsReference); + } + return false; + } + + internal bool IsEqualOrChecked(object other, Dictionary checkedContracts) + { + if ((object)this == other) + { + return true; + } + + if (checkedContracts != null) + { + DataContractPairKey contractPairKey = new DataContractPairKey(this, other); + if (checkedContracts.ContainsKey(contractPairKey)) + { + return true; + } + + checkedContracts.Add(contractPairKey, null); + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + internal void ThrowInvalidDataContractException(string message) + { + ThrowInvalidDataContractException(message, UnderlyingType); + } + + internal static bool IsTypeVisible(Type t) + { + // Generic parameters are always considered visible. + if (t.IsGenericParameter) + { + return true; + } + + // The normal Type.IsVisible check requires all nested types to be IsNestedPublic. + // This does not comply with our convention where they can also have InternalsVisibleTo + // with our assembly. The following method performs a recursive walk back the declaring + // type hierarchy to perform this enhanced IsVisible check. + if (!IsTypeAndDeclaringTypeVisible(t)) + { + return false; + } + + // All generic argument types must also be visible. + // Nested types perform this test recursively for all their declaring types. + foreach (Type genericType in t.GetGenericArguments()) + { + if (!IsTypeVisible(genericType)) + { + return false; + } + } + + return true; + } + + internal static bool IsTypeAndDeclaringTypeVisible(Type t) + { + // Arrays, etc. must consider the underlying element type because the + // non-element type does not reflect the same type nesting. For example, + // MyClass[] would not show as a nested type, even when MyClass is nested. + if (t.HasElementType) + { + return IsTypeVisible(t.GetElementType()); + } + + // Nested types are not visible unless their declaring type is visible. + // Additionally, they must be either IsNestedPublic or in an assembly with InternalsVisibleTo this current assembly. + // Non-nested types must be public or have this same InternalsVisibleTo relation. + return t.IsNested + ? (t.IsNestedPublic || IsTypeVisibleInSerializationModule(t)) && IsTypeVisible(t.DeclaringType) + : t.IsPublic || IsTypeVisibleInSerializationModule(t); + } + + internal static bool ConstructorRequiresMemberAccess(ConstructorInfo ctor) + { + return ctor != null && !ctor.IsPublic && !IsMemberVisibleInSerializationModule(ctor); + } + + internal static bool MethodRequiresMemberAccess(MethodInfo method) + { + return method != null && !method.IsPublic && !IsMemberVisibleInSerializationModule(method); + } + + internal static bool FieldRequiresMemberAccess(FieldInfo field) + { + return field != null && !field.IsPublic && !IsMemberVisibleInSerializationModule(field); + } + + private static bool IsTypeVisibleInSerializationModule(Type type) + { + return (type.Module.Equals(typeof(CodeGenerator).Module) || IsAssemblyFriendOfSerialization(type.Assembly)) && !type.IsNestedPrivate; + } + + private static bool IsMemberVisibleInSerializationModule(MemberInfo member) + { + if (!IsTypeVisibleInSerializationModule(member.DeclaringType)) + { + return false; + } + + if (member is MethodInfo method) + { + return (method.IsAssembly || method.IsFamilyOrAssembly); + } + else if (member is FieldInfo field) + { + return (field.IsAssembly || field.IsFamilyOrAssembly) && IsTypeVisible(field.FieldType); + } + else if (member is ConstructorInfo constructor) + { + return (constructor.IsAssembly || constructor.IsFamilyOrAssembly); + } + + return false; + } + + internal static bool IsAssemblyFriendOfSerialization(Assembly assembly) + { + InternalsVisibleToAttribute[] internalsVisibleAttributes = (InternalsVisibleToAttribute[])assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), false); + foreach (InternalsVisibleToAttribute internalsVisibleAttribute in internalsVisibleAttributes) + { + string internalsVisibleAttributeAssemblyName = internalsVisibleAttribute.AssemblyName; + + if (Regex.IsMatch(internalsVisibleAttributeAssemblyName, Globals.SimpleSRSInternalsVisiblePattern) || + Regex.IsMatch(internalsVisibleAttributeAssemblyName, Globals.FullSRSInternalsVisiblePattern)) + { + return true; + } + } + return false; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractPairKey.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractPairKey.cs new file mode 100644 index 0000000..46df9f8 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractPairKey.cs @@ -0,0 +1,30 @@ +namespace Compat.Runtime.Serialization +{ + internal class DataContractPairKey + { + private readonly object _object1; + private readonly object _object2; + + public DataContractPairKey(object object1, object object2) + { + _object1 = object1; + _object2 = object2; + } + + public override bool Equals(object other) + { + DataContractPairKey otherKey = other as DataContractPairKey; + if (otherKey == null) + { + return false; + } + + return ((otherKey._object1 == _object1 && otherKey._object2 == _object2) || (otherKey._object1 == _object2 && otherKey._object2 == _object1)); + } + + public override int GetHashCode() + { + return _object1.GetHashCode() ^ _object2.GetHashCode(); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializer.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializer.cs new file mode 100644 index 0000000..0719846 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializer.cs @@ -0,0 +1,522 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Xml; +using DataContractResolver = System.Runtime.Serialization.DataContractResolver; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + internal sealed class DataContractSerializer : XmlObjectSerializer + { + private Type _rootType; + private DataContract rootContract; // post-surrogate + private bool needsContractNsAtRoot; + private XmlDictionaryString rootName; + private XmlDictionaryString rootNamespace; + private int maxItemsInObjectGraph; + private bool ignoreExtensionDataObject; + private bool preserveObjectReferences; + private IDataContractSurrogate dataContractSurrogate; + private ReadOnlyCollection knownTypeCollection; + internal IList knownTypeList; + internal DataContractDictionary knownDataContracts; + private DataContractResolver dataContractResolver; + private bool serializeReadOnlyTypes; + + public DataContractSerializer(Type type) + : this(type, (IEnumerable)null) + { + } + + public DataContractSerializer(Type type, IEnumerable knownTypes) + : this(type, knownTypes, int.MaxValue, false, false, null) + { + } + + public DataContractSerializer(Type type, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate) + : this(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, null) + { + } + + public DataContractSerializer(Type type, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate, + DataContractResolver dataContractResolver) + { + Initialize(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, false); + } + + public DataContractSerializer(Type type, string rootName, string rootNamespace) + : this(type, rootName, rootNamespace, null) + { + } + + public DataContractSerializer(Type type, string rootName, string rootNamespace, IEnumerable knownTypes) + : this(type, rootName, rootNamespace, knownTypes, int.MaxValue, false, false, null) + { + } + + public DataContractSerializer(Type type, string rootName, string rootNamespace, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate) + : this(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, null) + { + } + + public DataContractSerializer(Type type, string rootName, string rootNamespace, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate, + DataContractResolver dataContractResolver) + { + XmlDictionary dictionary = new XmlDictionary(2); + Initialize(type, dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, false); + } + + public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace) + : this(type, rootName, rootNamespace, null) + { + } + + public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, IEnumerable knownTypes) + : this(type, rootName, rootNamespace, knownTypes, int.MaxValue, false, false, null, null) + { + } + + public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate) + : this(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, null) + { + } + + public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate, + DataContractResolver dataContractResolver) + { + Initialize(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, false); + } + + public DataContractSerializer(Type type, DataContractSerializerSettings settings) + { + if (settings == null) + { + settings = new DataContractSerializerSettings(); + } + Initialize(type, settings.RootName, settings.RootNamespace, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject, + settings.PreserveObjectReferences, settings.DataContractSurrogate, settings.DataContractResolver, settings.SerializeReadOnlyTypes); + } + + private void Initialize( + Type type, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate, + DataContractResolver dataContractResolver, + bool serializeReadOnlyTypes) + { + _rootType = type ?? throw new ArgumentNullException(nameof(type)); + + if (knownTypes != null) + { + knownTypeList = new List(); + foreach (Type knownType in knownTypes) + { + knownTypeList.Add(knownType); + } + } + + if (maxItemsInObjectGraph < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(maxItemsInObjectGraph), SR.ValueMustBeNonNegative)); + } + + this.maxItemsInObjectGraph = maxItemsInObjectGraph; + + this.ignoreExtensionDataObject = ignoreExtensionDataObject; + this.preserveObjectReferences = preserveObjectReferences; + this.dataContractSurrogate = dataContractSurrogate; + this.dataContractResolver = dataContractResolver; + this.serializeReadOnlyTypes = serializeReadOnlyTypes; + } + + private void Initialize(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace, + IEnumerable knownTypes, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + bool preserveObjectReferences, + IDataContractSurrogate dataContractSurrogate, + DataContractResolver dataContractResolver, + bool serializeReadOnlyTypes) + { + Initialize(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, dataContractSurrogate, dataContractResolver, serializeReadOnlyTypes); + // validate root name and namespace are both non-null + this.rootName = rootName; + this.rootNamespace = rootNamespace; + } + + public ReadOnlyCollection KnownTypes + { + get + { + if (knownTypeCollection == null) + { + if (knownTypeList != null) + { + knownTypeCollection = new ReadOnlyCollection(knownTypeList); + } + else + { + knownTypeCollection = new ReadOnlyCollection(Globals.EmptyTypeArray); + } + } + return knownTypeCollection; + } + } + + internal override DataContractDictionary KnownDataContracts + { + get + { + if (knownDataContracts == null && knownTypeList != null) + { + // This assignment may be performed concurrently and thus is a race condition. + // It's safe, however, because at worse a new (and identical) dictionary of + // data contracts will be created and re-assigned to this field. Introduction + // of a lock here could lead to deadlocks. + knownDataContracts = XmlObjectSerializerContext.GetDataContractsForKnownTypes(knownTypeList); + } + return knownDataContracts; + } + } + + public int MaxItemsInObjectGraph => maxItemsInObjectGraph; + + public IDataContractSurrogate DataContractSurrogate => dataContractSurrogate; + + public bool PreserveObjectReferences => preserveObjectReferences; + + public bool IgnoreExtensionDataObject => ignoreExtensionDataObject; + + public DataContractResolver DataContractResolver => dataContractResolver; + + public bool SerializeReadOnlyTypes => serializeReadOnlyTypes; + + private DataContract RootContract + { + get + { + if (rootContract == null) + { + rootContract = DataContract.GetDataContract(((dataContractSurrogate == null) ? _rootType : GetSurrogatedType(dataContractSurrogate, _rootType))); + needsContractNsAtRoot = CheckIfNeedsContractNsAtRoot(rootName, rootNamespace, rootContract); + } + return rootContract; + } + } + + internal override void InternalWriteObject(XmlWriterDelegator writer, object graph) + { + InternalWriteObject(writer, graph, null); + } + + internal override void InternalWriteObject(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver) + { + InternalWriteStartObject(writer, graph); + InternalWriteObjectContent(writer, graph, dataContractResolver); + InternalWriteEndObject(writer); + } + + public override void WriteObject(XmlWriter writer, object graph) + { + WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteStartObject(XmlWriter writer, object graph) + { + WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteObjectContent(XmlWriter writer, object graph) + { + WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteEndObject(XmlWriter writer) + { + WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer)); + } + + public override void WriteStartObject(XmlDictionaryWriter writer, object graph) + { + WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) + { + WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteEndObject(XmlDictionaryWriter writer) + { + WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer)); + } + + public void WriteObject(XmlDictionaryWriter writer, object graph, DataContractResolver dataContractResolver) + { + WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph, dataContractResolver); + } + + public override object ReadObject(XmlReader reader) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/); + } + + public override object ReadObject(XmlReader reader, bool verifyObjectName) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName); + } + + public override bool IsStartObject(XmlReader reader) + { + return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader)); + } + + public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName); + } + + public override bool IsStartObject(XmlDictionaryReader reader) + { + return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader)); + } + + public object ReadObject(XmlDictionaryReader reader, bool verifyObjectName, DataContractResolver dataContractResolver) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName, dataContractResolver); + } + + internal override void InternalWriteStartObject(XmlWriterDelegator writer, object graph) + { + WriteRootElement(writer, RootContract, rootName, rootNamespace, needsContractNsAtRoot); + } + + internal override void InternalWriteObjectContent(XmlWriterDelegator writer, object graph) + { + InternalWriteObjectContent(writer, graph, null); + } + + internal void InternalWriteObjectContent(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver) + { + if (MaxItemsInObjectGraph == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph))); + } + + DataContract contract = RootContract; + Type declaredType = contract.UnderlyingType; + Type graphType = (graph == null) ? declaredType : graph.GetType(); + + if (dataContractSurrogate != null) + { + graph = SurrogateToDataContractType(dataContractSurrogate, graph, declaredType, ref graphType); + } + + if (dataContractResolver == null) + { + dataContractResolver = DataContractResolver; + } + + if (graph == null) + { + if (IsRootXmlAny(rootName, contract)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsAnyCannotBeNull, declaredType))); + } + + WriteNull(writer); + } + else + { + if (declaredType == graphType) + { + if (contract.CanContainReferences) + { + XmlObjectSerializerWriteContext context = XmlObjectSerializerWriteContext.CreateContext(this, contract, dataContractResolver); + context.HandleGraphAtTopLevel(writer, graph, contract); + context.SerializeWithoutXsiType(contract, writer, graph, declaredType.TypeHandle); + } + else + { + contract.WriteXmlValue(writer, graph, null); + } + } + else + { + XmlObjectSerializerWriteContext context = null; + if (IsRootXmlAny(rootName, contract)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsAnyCannotBeSerializedAsDerivedType, graphType, contract.UnderlyingType))); + } + + contract = GetDataContract(contract, declaredType, graphType); + context = XmlObjectSerializerWriteContext.CreateContext(this, RootContract, dataContractResolver); + if (contract.CanContainReferences) + { + context.HandleGraphAtTopLevel(writer, graph, contract); + } + context.OnHandleIsReference(writer, contract, graph); + context.SerializeWithXsiTypeAtTopLevel(contract, writer, graph, declaredType.TypeHandle, graphType); + } + } + } + + internal static DataContract GetDataContract(DataContract declaredTypeContract, Type declaredType, Type objectType) + { + if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType)) + { + return declaredTypeContract; + } + else if (declaredType.IsArray)//Array covariance is not supported in XSD + { + return declaredTypeContract; + } + else + { + return DataContract.GetDataContract(objectType.TypeHandle, objectType, SerializationMode.SharedContract); + } + } + + internal void SetDataContractSurrogate(IDataContractSurrogate adapter) + { + dataContractSurrogate = adapter; + } + + internal override void InternalWriteEndObject(XmlWriterDelegator writer) + { + if (!IsRootXmlAny(rootName, RootContract)) + { + writer.WriteEndElement(); + } + } + + internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName) + { + return InternalReadObject(xmlReader, verifyObjectName, null); + } + + internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName, DataContractResolver dataContractResolver) + { + if (MaxItemsInObjectGraph == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph))); + } + + if (dataContractResolver == null) + { + dataContractResolver = DataContractResolver; + } + + if (verifyObjectName) + { + if (!InternalIsStartObject(xmlReader)) + { + XmlDictionaryString expectedName; + XmlDictionaryString expectedNs; + if (rootName == null) + { + expectedName = RootContract.TopLevelElementName; + expectedNs = RootContract.TopLevelElementNamespace; + } + else + { + expectedName = rootName; + expectedNs = rootNamespace; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.Format(SR.ExpectingElement, expectedNs, expectedName), xmlReader)); + } + } + else if (!IsStartElement(xmlReader)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.Format(SR.ExpectingElementAtDeserialize, XmlNodeType.Element), xmlReader)); + } + + DataContract contract = RootContract; + if (contract.IsPrimitive && object.ReferenceEquals(contract.UnderlyingType, _rootType) /*handle Nullable differently*/) + { + return contract.ReadXmlValue(xmlReader, null); + } + + if (IsRootXmlAny(rootName, contract)) + { + return XmlObjectSerializerReadContext.ReadRootIXmlSerializable(xmlReader, contract as XmlDataContract, false /*isMemberType*/); + } + + XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext.CreateContext(this, contract, dataContractResolver); + return context.InternalDeserialize(xmlReader, _rootType, contract, null, null); + } + + internal override bool InternalIsStartObject(XmlReaderDelegator reader) + { + return IsRootElement(reader, RootContract, rootName, rootNamespace); + } + + internal override Type GetSerializeType(object graph) + { + return (graph == null) ? _rootType : graph.GetType(); + } + + internal override Type GetDeserializeType() + { + return _rootType; + } + + internal static object SurrogateToDataContractType(IDataContractSurrogate dataContractSurrogate, object oldObj, Type surrogatedDeclaredType, ref Type objType) + { + object obj = DataContractSurrogateCaller.GetObjectToSerialize(dataContractSurrogate, oldObj, objType, surrogatedDeclaredType); + if (obj != oldObj) + { + if (obj == null) + { + objType = Globals.TypeOfObject; + } + else + { + objType = obj.GetType(); + } + } + return obj; + } + + internal static Type GetSurrogatedType(IDataContractSurrogate dataContractSurrogate, Type type) + { + return DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, DataContract.UnwrapNullableType(type)); + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializerSettings.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializerSettings.cs new file mode 100644 index 0000000..e8168b5 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSerializerSettings.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using DataContractResolver = System.Runtime.Serialization.DataContractResolver; + +namespace Compat.Runtime.Serialization +{ + public class DataContractSerializerSettings + { + /// + /// Gets or sets Dummy documentation + /// + public XmlDictionaryString RootName { get; set; } + + /// + /// Gets or sets Dummy documentation + /// + public XmlDictionaryString RootNamespace { get; set; } + + /// + /// Gets or sets Dummy documentation + /// + public IEnumerable KnownTypes { get; set; } + + /// + /// Gets or sets Dummy documentation + /// + public int MaxItemsInObjectGraph { get; set; } = int.MaxValue; + + /// + /// Gets or sets a value indicating whether Dummy documentation + /// + public bool IgnoreExtensionDataObject { get; set; } + + /// + /// Gets or sets a value indicating whether Dummy documentation + /// + public bool PreserveObjectReferences { get; set; } + + /// + /// Gets or sets Dummy documentation + /// + internal IDataContractSurrogate DataContractSurrogate { get; set; } + + /// + /// Gets or sets Dummy documentation + /// + public DataContractResolver DataContractResolver { get; set; } + + /// + /// Gets or sets a value indicating whether Dummy documentation + /// + public bool SerializeReadOnlyTypes { get; set; } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSet.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSet.cs new file mode 100644 index 0000000..6d61bb0 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSet.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + + internal class DataContractSet + { + private Dictionary contracts; + private Dictionary processedContracts; + private readonly IDataContractSurrogate dataContractSurrogate; + private Hashtable surrogateDataTable; + private DataContractDictionary knownTypesForObject; + private readonly ICollection referencedTypes; + private readonly ICollection referencedCollectionTypes; + private Dictionary referencedTypesDictionary; + private Dictionary referencedCollectionTypesDictionary; + + + internal DataContractSet(IDataContractSurrogate dataContractSurrogate) : this(dataContractSurrogate, null, null) { } + + internal DataContractSet(IDataContractSurrogate dataContractSurrogate, ICollection referencedTypes, ICollection referencedCollectionTypes) + { + this.dataContractSurrogate = dataContractSurrogate; + this.referencedTypes = referencedTypes; + this.referencedCollectionTypes = referencedCollectionTypes; + } + + internal DataContractSet(DataContractSet dataContractSet) + { + if (dataContractSet == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("dataContractSet")); + } + + dataContractSurrogate = dataContractSet.dataContractSurrogate; + referencedTypes = dataContractSet.referencedTypes; + referencedCollectionTypes = dataContractSet.referencedCollectionTypes; + + foreach (KeyValuePair pair in dataContractSet) + { + Add(pair.Key, pair.Value); + } + + if (dataContractSet.processedContracts != null) + { + foreach (KeyValuePair pair in dataContractSet.processedContracts) + { + ProcessedContracts.Add(pair.Key, pair.Value); + } + } + } + + private Dictionary Contracts + { + get + { + if (contracts == null) + { + contracts = new Dictionary(); + } + return contracts; + } + } + + private Dictionary ProcessedContracts + { + get + { + if (processedContracts == null) + { + processedContracts = new Dictionary(); + } + return processedContracts; + } + } + + private Hashtable SurrogateDataTable + { + get + { + if (surrogateDataTable == null) + { + surrogateDataTable = new Hashtable(); + } + + return surrogateDataTable; + } + } + + internal DataContractDictionary KnownTypesForObject + { + get => knownTypesForObject; + set => knownTypesForObject = value; + } + + internal void Add(Type type) + { + DataContract dataContract = GetDataContract(type); + EnsureTypeNotGeneric(dataContract.UnderlyingType); + Add(dataContract); + } + + internal static void EnsureTypeNotGeneric(Type type) + { + if (type.ContainsGenericParameters) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); + } + } + + private void Add(DataContract dataContract) + { + Add(dataContract.StableName, dataContract); + } + + public void Add(XmlQualifiedName name, DataContract dataContract) + { + if (dataContract.IsBuiltInDataContract) + { + return; + } + + InternalAdd(name, dataContract); + } + + internal void InternalAdd(XmlQualifiedName name, DataContract dataContract) + { + if (Contracts.TryGetValue(name, out DataContract dataContractInSet)) + { + if (!dataContractInSet.Equals(dataContract)) + { + if (dataContract.UnderlyingType == null || dataContractInSet.UnderlyingType == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInDataContractSet, dataContract.StableName.Name, dataContract.StableName.Namespace))); + } + else + { + bool typeNamesEqual = (DataContract.GetClrTypeFullName(dataContract.UnderlyingType) == DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupTypeContractInDataContractSet, (typeNamesEqual ? dataContract.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContract.UnderlyingType)), (typeNamesEqual ? dataContractInSet.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)), dataContract.StableName.Name, dataContract.StableName.Namespace))); + } + } + } + else + { + Contracts.Add(name, dataContract); + + if (dataContract is ClassDataContract) + { + AddClassDataContract((ClassDataContract)dataContract); + } + else if (dataContract is CollectionDataContract) + { + AddCollectionDataContract((CollectionDataContract)dataContract); + } + else if (dataContract is XmlDataContract) + { + AddXmlDataContract((XmlDataContract)dataContract); + } + } + } + + private void AddClassDataContract(ClassDataContract classDataContract) + { + if (classDataContract.BaseContract != null) + { + Add(classDataContract.BaseContract.StableName, classDataContract.BaseContract); + } + if (!classDataContract.IsISerializable) + { + if (classDataContract.Members != null) + { + for (int i = 0; i < classDataContract.Members.Count; i++) + { + DataMember dataMember = classDataContract.Members[i]; + DataContract memberDataContract = GetMemberTypeDataContract(dataMember); + if (dataContractSurrogate != null && dataMember.MemberInfo != null) + { + object customData = DataContractSurrogateCaller.GetCustomDataToExport( + dataContractSurrogate, + dataMember.MemberInfo, + memberDataContract.UnderlyingType); + if (customData != null) + { + SurrogateDataTable.Add(dataMember, customData); + } + } + Add(memberDataContract.StableName, memberDataContract); + } + } + } + AddKnownDataContracts(classDataContract.KnownDataContracts); + } + + private void AddCollectionDataContract(CollectionDataContract collectionDataContract) + { + if (collectionDataContract.IsDictionary) + { + ClassDataContract keyValueContract = collectionDataContract.ItemContract as ClassDataContract; + AddClassDataContract(keyValueContract); + } + else + { + DataContract itemContract = GetItemTypeDataContract(collectionDataContract); + if (itemContract != null) + { + Add(itemContract.StableName, itemContract); + } + } + AddKnownDataContracts(collectionDataContract.KnownDataContracts); + } + + private void AddXmlDataContract(XmlDataContract xmlDataContract) + { + AddKnownDataContracts(xmlDataContract.KnownDataContracts); + } + + private void AddKnownDataContracts(DataContractDictionary knownDataContracts) + { + if (knownDataContracts != null) + { + foreach (DataContract knownDataContract in knownDataContracts.Values) + { + Add(knownDataContract); + } + } + } + + internal XmlQualifiedName GetStableName(Type clrType) + { + if (dataContractSurrogate != null) + { + Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, clrType); + return DataContract.GetStableName(dcType); + } + return DataContract.GetStableName(clrType); + } + + internal DataContract GetDataContract(Type clrType) + { + if (dataContractSurrogate == null) + { + return DataContract.GetDataContract(clrType); + } + + DataContract dataContract = DataContract.GetBuiltInDataContract(clrType); + if (dataContract != null) + { + return dataContract; + } + + Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, clrType); + dataContract = DataContract.GetDataContract(dcType); + if (!SurrogateDataTable.Contains(dataContract)) + { + object customData = DataContractSurrogateCaller.GetCustomDataToExport( + dataContractSurrogate, clrType, dcType); + if (customData != null) + { + SurrogateDataTable.Add(dataContract, customData); + } + } + return dataContract; + } + + internal DataContract GetMemberTypeDataContract(DataMember dataMember) + { + if (dataMember.MemberInfo != null) + { + Type dataMemberType = dataMember.MemberType; + if (dataMember.IsGetOnlyCollection) + { + if (dataContractSurrogate != null) + { + Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, dataMemberType); + if (dcType != dataMemberType) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupported, + DataContract.GetClrTypeFullName(dataMemberType), DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType), dataMember.MemberInfo.Name))); + } + } + return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType, SerializationMode.SharedContract); + } + else + { + return GetDataContract(dataMemberType); + } + } + return dataMember.MemberTypeContract; + } + + internal DataContract GetItemTypeDataContract(CollectionDataContract collectionContract) + { + if (collectionContract.ItemType != null) + { + return GetDataContract(collectionContract.ItemType); + } + + return collectionContract.ItemContract; + } + + internal object GetSurrogateData(object key) + { + return SurrogateDataTable[key]; + } + + internal void SetSurrogateData(object key, object surrogateData) + { + SurrogateDataTable[key] = surrogateData; + } + + public DataContract this[XmlQualifiedName key] + { + get + { + DataContract dataContract = DataContract.GetBuiltInDataContract(key.Name, key.Namespace); + if (dataContract == null) + { + Contracts.TryGetValue(key, out dataContract); + } + return dataContract; + } + } + + public IDataContractSurrogate DataContractSurrogate => dataContractSurrogate; + + public bool Remove(XmlQualifiedName key) + { + if (DataContract.GetBuiltInDataContract(key.Name, key.Namespace) != null) + { + return false; + } + + return Contracts.Remove(key); + } + + public IEnumerator> GetEnumerator() + { + return Contracts.GetEnumerator(); + } + + internal bool IsContractProcessed(DataContract dataContract) + { + return ProcessedContracts.ContainsKey(dataContract); + } + + internal void SetContractProcessed(DataContract dataContract) + { + ProcessedContracts.Add(dataContract, dataContract); + } + + private Dictionary GetReferencedTypes() + { + if (referencedTypesDictionary == null) + { + referencedTypesDictionary = new Dictionary + { + //Always include Nullable as referenced type + //Do not allow surrogating Nullable + { DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable } + }; + if (referencedTypes != null) + { + foreach (Type type in referencedTypes) + { + if (type == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.ReferencedTypesCannotContainNull)); + } + + AddReferencedType(referencedTypesDictionary, type); + } + } + } + return referencedTypesDictionary; + } + + private Dictionary GetReferencedCollectionTypes() + { + if (referencedCollectionTypesDictionary == null) + { + referencedCollectionTypesDictionary = new Dictionary(); + if (referencedCollectionTypes != null) + { + foreach (Type type in referencedCollectionTypes) + { + if (type == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.ReferencedCollectionTypesCannotContainNull)); + } + + AddReferencedType(referencedCollectionTypesDictionary, type); + } + } + XmlQualifiedName genericDictionaryName = DataContract.GetStableName(Globals.TypeOfDictionaryGeneric); + if (!referencedCollectionTypesDictionary.ContainsKey(genericDictionaryName) && GetReferencedTypes().ContainsKey(genericDictionaryName)) + { + AddReferencedType(referencedCollectionTypesDictionary, Globals.TypeOfDictionaryGeneric); + } + } + return referencedCollectionTypesDictionary; + } + + private void AddReferencedType(Dictionary referencedTypes, Type type) + { + if (IsTypeReferenceable(type)) + { + XmlQualifiedName stableName; + try + { + stableName = GetStableName(type); + } + catch (InvalidDataContractException) + { + // Type not referenceable if we can't get a stable name. + return; + } + catch (InvalidOperationException) + { + // Type not referenceable if we can't get a stable name. + return; + } + + if (referencedTypes.TryGetValue(stableName, out object value)) + { + Type referencedType = value as Type; + if (referencedType != null) + { + if (referencedType != type) + { + referencedTypes.Remove(stableName); + List types = new List + { + referencedType, + type + }; + referencedTypes.Add(stableName, types); + } + } + else + { + List types = (List)value; + if (!types.Contains(type)) + { + types.Add(type); + } + } + } + else + { + referencedTypes.Add(stableName, type); + } + } + } + internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, out Type type) + { + return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type); + } + + internal bool TryGetReferencedCollectionType(XmlQualifiedName stableName, DataContract dataContract, out Type type) + { + return TryGetReferencedType(stableName, dataContract, true/*useReferencedCollectionTypes*/, out type); + } + + private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, bool useReferencedCollectionTypes, out Type type) + { + Dictionary referencedTypes = useReferencedCollectionTypes ? GetReferencedCollectionTypes() : GetReferencedTypes(); + if (referencedTypes.TryGetValue(stableName, out object value)) + { + type = value as Type; + if (type != null) + { + return true; + } + else + { + // Throw ambiguous type match exception + List types = (List)value; + StringBuilder errorMessage = new StringBuilder(); + bool containsGenericType = false; + for (int i = 0; i < types.Count; i++) + { + Type conflictingType = types[i]; + if (!containsGenericType) + { + containsGenericType = conflictingType.IsGenericTypeDefinition; + } + + errorMessage.AppendFormat("{0}\"{1}\" ", Environment.NewLine, conflictingType.AssemblyQualifiedName); + if (dataContract != null) + { + DataContract other = GetDataContract(conflictingType); + errorMessage.Append(SR.Format(((other != null && other.Equals(dataContract)) ? SR.ReferencedTypeMatchingMessage : SR.ReferencedTypeNotMatchingMessage))); + } + } + if (containsGenericType) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format( + (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes1 : SR.AmbiguousReferencedTypes1), + errorMessage.ToString()))); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format( + (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes3 : SR.AmbiguousReferencedTypes3), + XmlConvert.DecodeName(stableName.Name), + stableName.Namespace, + errorMessage.ToString()))); + } + } + } + type = null; + return false; + } + + private static bool IsTypeReferenceable(Type type) + { + + try + { + return (type.IsSerializable || + type.IsDefined(Globals.TypeOfDataContractAttribute, false) || + (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) && !type.IsGenericTypeDefinition) || + CollectionDataContract.IsCollection(type, out Type itemType) || + ClassDataContract.IsNonAttributedTypeValidForSerialization(type)); + } + catch (Exception ex) + { + // An exception can be thrown in the designer when a project has a runtime binding redirection for a referenced assembly or a reference dependent assembly. + // Type.IsDefined is known to throw System.IO.FileLoadException. + // ClassDataContract.IsNonAttributedTypeValidForSerialization is known to throw System.IO.FileNotFoundException. + // We guard against all non-critical exceptions. + if (Fx.IsFatal(ex)) + { + throw; + } + } + + return false; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSurrogateCaller.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSurrogateCaller.cs new file mode 100644 index 0000000..7c12c26 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataContractSurrogateCaller.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.ObjectModel; +using System.Reflection; + +namespace Compat.Runtime.Serialization +{ + internal static class DataContractSurrogateCaller + { + internal static Type GetDataContractType(IDataContractSurrogate surrogate, Type type) + { + if (DataContract.GetBuiltInDataContract(type) != null) + { + return type; + } + + Type dcType = surrogate.GetDataContractType(type); + if (dcType == null) + { + return type; + } + + return dcType; + + } + internal static object GetObjectToSerialize(IDataContractSurrogate surrogate, object obj, Type objType, Type membertype) + { + if (obj == null) + { + return null; + } + + if (DataContract.GetBuiltInDataContract(objType) != null) + { + return obj; + } + + return surrogate.GetObjectToSerialize(obj, membertype); + } + internal static object GetDeserializedObject(IDataContractSurrogate surrogate, object obj, Type objType, Type memberType) + { + if (obj == null) + { + return null; + } + + if (DataContract.GetBuiltInDataContract(objType) != null) + { + return obj; + } + + return surrogate.GetDeserializedObject(obj, memberType); + } + internal static object GetCustomDataToExport(IDataContractSurrogate surrogate, MemberInfo memberInfo, Type dataContractType) + { + return surrogate.GetCustomDataToExport(memberInfo, dataContractType); + } + internal static object GetCustomDataToExport(IDataContractSurrogate surrogate, Type clrType, Type dataContractType) + { + if (DataContract.GetBuiltInDataContract(clrType) != null) + { + return null; + } + + return surrogate.GetCustomDataToExport(clrType, dataContractType); + } + internal static void GetKnownCustomDataTypes(IDataContractSurrogate surrogate, Collection customDataTypes) + { + surrogate.GetKnownCustomDataTypes(customDataTypes); + } + internal static Type GetReferencedTypeOnImport(IDataContractSurrogate surrogate, string typeName, string typeNamespace, object customData) + { + if (DataContract.GetBuiltInDataContract(typeName, typeNamespace) != null) + { + return null; + } + + return surrogate.GetReferencedTypeOnImport(typeName, typeNamespace, customData); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataMember.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataMember.cs new file mode 100644 index 0000000..4f9daa8 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataMember.cs @@ -0,0 +1,295 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Compat.Runtime.Serialization +{ + internal class DataMember + { + private readonly CriticalHelper helper; + + internal DataMember() + { + helper = new CriticalHelper(); + } + + internal DataMember(MemberInfo memberInfo) + { + helper = new CriticalHelper(memberInfo); + } + + internal DataMember(string name) + { + helper = new CriticalHelper(name); + } + + internal DataMember(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, int order) + { + helper = new CriticalHelper(memberTypeContract, name, isNullable, isRequired, emitDefaultValue, order); + } + + internal MemberInfo MemberInfo => helper.MemberInfo; + + internal string Name + { + get => helper.Name; + set => helper.Name = value; + } + + internal int Order + { + get => helper.Order; + set => helper.Order = value; + } + + internal bool IsRequired + { + get => helper.IsRequired; + set => helper.IsRequired = value; + } + + internal bool EmitDefaultValue + { + get => helper.EmitDefaultValue; + set => helper.EmitDefaultValue = value; + } + + internal bool IsNullable + { + get => helper.IsNullable; + set => helper.IsNullable = value; + } + + internal bool IsGetOnlyCollection + { + get => helper.IsGetOnlyCollection; + set => helper.IsGetOnlyCollection = value; + } + + internal Type MemberType => helper.MemberType; + + internal DataContract MemberTypeContract + { + get => helper.MemberTypeContract; + set => helper.MemberTypeContract = value; + } + + internal bool HasConflictingNameAndType + { + get => helper.HasConflictingNameAndType; + set => helper.HasConflictingNameAndType = value; + } + + internal DataMember ConflictingMember + { + get => helper.ConflictingMember; + set => helper.ConflictingMember = value; + } + + private class CriticalHelper + { + private DataContract memberTypeContract; + private string name; + private int order; + private bool isRequired; + private bool emitDefaultValue; + private bool isNullable; + private bool isGetOnlyCollection = false; + private readonly MemberInfo memberInfo; + private bool hasConflictingNameAndType; + private DataMember conflictingMember; + + internal CriticalHelper() + { + emitDefaultValue = Globals.DefaultEmitDefaultValue; + } + + internal CriticalHelper(MemberInfo memberInfo) + { + emitDefaultValue = Globals.DefaultEmitDefaultValue; + this.memberInfo = memberInfo; + } + + internal CriticalHelper(string name) + { + Name = name; + } + + internal CriticalHelper(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, int order) + { + MemberTypeContract = memberTypeContract; + Name = name; + IsNullable = isNullable; + IsRequired = isRequired; + EmitDefaultValue = emitDefaultValue; + Order = order; + } + + internal MemberInfo MemberInfo => memberInfo; + + internal string Name + { + get => name; + set => name = value; + } + + internal int Order + { + get => order; + set => order = value; + } + + internal bool IsRequired + { + get => isRequired; + set => isRequired = value; + } + + internal bool EmitDefaultValue + { + get => emitDefaultValue; + set => emitDefaultValue = value; + } + + internal bool IsNullable + { + get => isNullable; + set => isNullable = value; + } + + internal bool IsGetOnlyCollection + { + get => isGetOnlyCollection; + set => isGetOnlyCollection = value; + } + + internal Type MemberType + { + get + { + FieldInfo field = MemberInfo as FieldInfo; + if (field != null) + { + return field.FieldType; + } + + return ((PropertyInfo)MemberInfo).PropertyType; + } + } + + internal DataContract MemberTypeContract + { + get + { + if (memberTypeContract == null) + { + if (MemberInfo != null) + { + if (IsGetOnlyCollection) + { + memberTypeContract = DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(MemberType.TypeHandle), MemberType.TypeHandle, MemberType, SerializationMode.SharedContract); + } + else + { + memberTypeContract = DataContract.GetDataContract(MemberType); + } + } + } + return memberTypeContract; + } + set => memberTypeContract = value; + } + + internal bool HasConflictingNameAndType + { + get => hasConflictingNameAndType; + set => hasConflictingNameAndType = value; + } + + internal DataMember ConflictingMember + { + get => conflictingMember; + set => conflictingMember = value; + } + } + + internal bool RequiresMemberAccessForGet() + { + MemberInfo memberInfo = MemberInfo; + FieldInfo field = memberInfo as FieldInfo; + if (field != null) + { + return DataContract.FieldRequiresMemberAccess(field); + } + else + { + PropertyInfo property = (PropertyInfo)memberInfo; + MethodInfo getMethod = property.GetGetMethod(true /*nonPublic*/); + if (getMethod != null) + { + return DataContract.MethodRequiresMemberAccess(getMethod) || !DataContract.IsTypeVisible(property.PropertyType); + } + } + return false; + } + + internal bool RequiresMemberAccessForSet() + { + MemberInfo memberInfo = MemberInfo; + FieldInfo field = memberInfo as FieldInfo; + if (field != null) + { + return DataContract.FieldRequiresMemberAccess(field); + } + else + { + PropertyInfo property = (PropertyInfo)memberInfo; + MethodInfo setMethod = property.GetSetMethod(true /*nonPublic*/); + if (setMethod != null) + { + return DataContract.MethodRequiresMemberAccess(setMethod) || !DataContract.IsTypeVisible(property.PropertyType); + } + } + return false; + } + + internal DataMember BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + DataContract memberTypeContract = MemberTypeContract.BindGenericParameters(paramContracts, boundContracts); + DataMember boundDataMember = new DataMember(memberTypeContract, + Name, + !memberTypeContract.IsValueType, + IsRequired, + EmitDefaultValue, + Order); + return boundDataMember; + } + + internal bool Equals(object other, Dictionary checkedContracts) + { + if ((object)this == other) + { + return true; + } + + DataMember dataMember = other as DataMember; + if (dataMember != null) + { + // Note: comparison does not use Order hint since it influences element order but does not specify exact order + bool thisIsNullable = (MemberTypeContract == null) ? false : !MemberTypeContract.IsValueType; + bool dataMemberIsNullable = (dataMember.MemberTypeContract == null) ? false : !dataMember.MemberTypeContract.IsValueType; + return (Name == dataMember.Name + && (IsNullable || thisIsNullable) == (dataMember.IsNullable || dataMemberIsNullable) + && IsRequired == dataMember.IsRequired + && EmitDefaultValue == dataMember.EmitDefaultValue + && MemberTypeContract.Equals(dataMember.MemberTypeContract, checkedContracts)); + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DataNode`1.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataNode`1.cs new file mode 100644 index 0000000..1e8cb8f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DataNode`1.cs @@ -0,0 +1,132 @@ +using System; +using System.Globalization; + +namespace Compat.Runtime.Serialization +{ + internal class DataNode : IDataNode + { + protected Type dataType; + private T _value; + private string _dataContractName; + private string _dataContractNamespace; + private string _clrTypeName; + private string _clrAssemblyName; + private string _id = Globals.NewObjectId; + private bool _isFinalValue; + + internal DataNode() + { + dataType = typeof(T); + _isFinalValue = true; + } + + internal DataNode(T value) + : this() + { + _value = value; + } + + public Type DataType => dataType; + + public object Value + { + get => _value; + set => _value = (T)value; + } + + bool IDataNode.IsFinalValue + { + get => _isFinalValue; + set => _isFinalValue = value; + } + + public T GetValue() + { + return _value; + } + + public string DataContractName + { + get => _dataContractName; + set => _dataContractName = value; + } + + public string DataContractNamespace + { + get => _dataContractNamespace; + set => _dataContractNamespace = value; + } + + public string ClrTypeName + { + get => _clrTypeName; + set => _clrTypeName = value; + } + + public string ClrAssemblyName + { + get => _clrAssemblyName; + set => _clrAssemblyName = value; + } + + public bool PreservesReferences => (Id != Globals.NewObjectId); + + public string Id + { + get => _id; + set => _id = value; + } + + public virtual void GetData(ElementData element) + { + element.dataNode = this; + element.attributeCount = 0; + element.childElementIndex = 0; + + if (DataContractName != null) + { + AddQualifiedNameAttribute(element, Globals.XsiPrefix, Globals.XsiTypeLocalName, Globals.SchemaInstanceNamespace, DataContractName, DataContractNamespace); + } + + if (ClrTypeName != null) + { + element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ClrTypeLocalName, ClrTypeName); + } + + if (ClrAssemblyName != null) + { + element.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.ClrAssemblyLocalName, ClrAssemblyName); + } + } + + public virtual void Clear() + { + // dataContractName not cleared because it is used when re-serializing from unknown data + _clrTypeName = _clrAssemblyName = null; + } + + internal void AddQualifiedNameAttribute(ElementData element, string elementPrefix, string elementName, string elementNs, string valueName, string valueNs) + { + string prefix = ExtensionDataReader.GetPrefix(valueNs); + element.AddAttribute(elementPrefix, elementNs, elementName, string.Format(CultureInfo.InvariantCulture, "{0}:{1}", prefix, valueName)); + + bool prefixDeclaredOnElement = false; + if (element.attributes != null) + { + for (int i = 0; i < element.attributes.Length; i++) + { + AttributeData attribute = element.attributes[i]; + if (attribute != null && attribute.prefix == Globals.XmlnsPrefix && attribute.localName == prefix) + { + prefixDeclaredOnElement = true; + break; + } + } + } + if (!prefixDeclaredOnElement) + { + element.AddAttribute(Globals.XmlnsPrefix, Globals.XmlnsNamespace, prefix, valueNs); + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DateTimeOffsetAdapter.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DateTimeOffsetAdapter.cs new file mode 100644 index 0000000..3c8b1df --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DateTimeOffsetAdapter.cs @@ -0,0 +1,70 @@ +using Compat.Xml; +using System; +using System.Globalization; +using DataContractAttribute = System.Runtime.Serialization.DataContractAttribute; +using DataMemberAttribute = System.Runtime.Serialization.DataMemberAttribute; + +namespace Compat.Runtime.Serialization +{ + [DataContract(Name = "DateTimeOffset", Namespace = "http://schemas.datacontract.org/2004/07/System")] + internal struct DateTimeOffsetAdapter + { + private DateTime _utcDateTime; + private short _offsetMinutes; + + public DateTimeOffsetAdapter(DateTime dateTime, short offsetMinutes) + { + _utcDateTime = dateTime; + _offsetMinutes = offsetMinutes; + } + + [DataMember(Name = "DateTime", IsRequired = true)] + public DateTime UtcDateTime + { + get => _utcDateTime; + set => _utcDateTime = value; + } + + [DataMember(Name = "OffsetMinutes", IsRequired = true)] + public short OffsetMinutes + { + get => _offsetMinutes; + set => _offsetMinutes = value; + } + + public static DateTimeOffset GetDateTimeOffset(DateTimeOffsetAdapter value) + { + try + { + switch (value.UtcDateTime.Kind) + { + case DateTimeKind.Unspecified: + return new DateTimeOffset(value.UtcDateTime, new TimeSpan(0, value.OffsetMinutes, 0)); + + //DateTimeKind.Utc and DateTimeKind.Local + //Read in deserialized DateTime portion of the DateTimeOffsetAdapter and convert DateTimeKind to Unspecified. + //Apply ofset information read from OffsetMinutes portion of the DateTimeOffsetAdapter. + //Return converted DateTimeoffset object. + default: + DateTimeOffset deserialized = new DateTimeOffset(value.UtcDateTime); + return deserialized.ToOffset(new TimeSpan(0, value.OffsetMinutes, 0)); + } + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value.ToString(CultureInfo.InvariantCulture), "DateTimeOffset", exception)); + } + } + + public static DateTimeOffsetAdapter GetDateTimeOffsetAdapter(DateTimeOffset value) + { + return new DateTimeOffsetAdapter(value.UtcDateTime, (short)value.Offset.TotalMinutes); + } + + public string ToString(IFormatProvider provider) + { + return "DateTime: " + UtcDateTime + ", Offset: " + OffsetMinutes; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DiagnosticUtility.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DiagnosticUtility.cs new file mode 100644 index 0000000..e132922 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DiagnosticUtility.cs @@ -0,0 +1,27 @@ +using System; +using System.Diagnostics; + +namespace Compat.Runtime.Serialization +{ + internal class DiagnosticUtility + { + public class ExceptionUtility + { + internal static Exception ThrowHelperFatal(string message, Exception innerException) + { + return ThrowHelperError(new FatalException(message, innerException)); + } + + internal static Exception ThrowHelperError(Exception exception) + { + return ThrowHelper(exception, TraceEventType.Error); + } + + internal static Exception ThrowHelper(Exception exception, TraceEventType eventType) + { + return exception; + } + + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/DictionaryGlobals.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/DictionaryGlobals.cs new file mode 100644 index 0000000..598b1a0 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/DictionaryGlobals.cs @@ -0,0 +1,178 @@ +using System; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal static class DictionaryGlobals + { + public readonly static XmlDictionaryString EmptyString; + public readonly static XmlDictionaryString SchemaInstanceNamespace; + public readonly static XmlDictionaryString SchemaNamespace; + public readonly static XmlDictionaryString SerializationNamespace; + public readonly static XmlDictionaryString XmlnsNamespace; + public readonly static XmlDictionaryString XsiTypeLocalName; + public readonly static XmlDictionaryString XsiNilLocalName; + public readonly static XmlDictionaryString ClrTypeLocalName; + public readonly static XmlDictionaryString ClrAssemblyLocalName; + public readonly static XmlDictionaryString ArraySizeLocalName; + public readonly static XmlDictionaryString IdLocalName; + public readonly static XmlDictionaryString RefLocalName; + public readonly static XmlDictionaryString ISerializableFactoryTypeLocalName; + public readonly static XmlDictionaryString CharLocalName; + public readonly static XmlDictionaryString BooleanLocalName; + public readonly static XmlDictionaryString SignedByteLocalName; + public readonly static XmlDictionaryString UnsignedByteLocalName; + public readonly static XmlDictionaryString ShortLocalName; + public readonly static XmlDictionaryString UnsignedShortLocalName; + public readonly static XmlDictionaryString IntLocalName; + public readonly static XmlDictionaryString UnsignedIntLocalName; + public readonly static XmlDictionaryString LongLocalName; + public readonly static XmlDictionaryString UnsignedLongLocalName; + public readonly static XmlDictionaryString FloatLocalName; + public readonly static XmlDictionaryString DoubleLocalName; + public readonly static XmlDictionaryString DecimalLocalName; + public readonly static XmlDictionaryString DateTimeLocalName; + public readonly static XmlDictionaryString StringLocalName; + public readonly static XmlDictionaryString ByteArrayLocalName; + public readonly static XmlDictionaryString ObjectLocalName; + public readonly static XmlDictionaryString TimeSpanLocalName; + public readonly static XmlDictionaryString GuidLocalName; + public readonly static XmlDictionaryString UriLocalName; + public readonly static XmlDictionaryString QNameLocalName; + public readonly static XmlDictionaryString Space; + + public readonly static XmlDictionaryString timeLocalName; + public readonly static XmlDictionaryString dateLocalName; + public readonly static XmlDictionaryString hexBinaryLocalName; + public readonly static XmlDictionaryString gYearMonthLocalName; + public readonly static XmlDictionaryString gYearLocalName; + public readonly static XmlDictionaryString gMonthDayLocalName; + public readonly static XmlDictionaryString gDayLocalName; + public readonly static XmlDictionaryString gMonthLocalName; + public readonly static XmlDictionaryString integerLocalName; + public readonly static XmlDictionaryString positiveIntegerLocalName; + public readonly static XmlDictionaryString negativeIntegerLocalName; + public readonly static XmlDictionaryString nonPositiveIntegerLocalName; + public readonly static XmlDictionaryString nonNegativeIntegerLocalName; + public readonly static XmlDictionaryString normalizedStringLocalName; + public readonly static XmlDictionaryString tokenLocalName; + public readonly static XmlDictionaryString languageLocalName; + public readonly static XmlDictionaryString NameLocalName; + public readonly static XmlDictionaryString NCNameLocalName; + public readonly static XmlDictionaryString XSDIDLocalName; + public readonly static XmlDictionaryString IDREFLocalName; + public readonly static XmlDictionaryString IDREFSLocalName; + public readonly static XmlDictionaryString ENTITYLocalName; + public readonly static XmlDictionaryString ENTITIESLocalName; + public readonly static XmlDictionaryString NMTOKENLocalName; + public readonly static XmlDictionaryString NMTOKENSLocalName; + public readonly static XmlDictionaryString AsmxTypesNamespace; + + static DictionaryGlobals() + { + // Update array size when adding new strings or templates + XmlDictionary dictionary = new XmlDictionary(61); + + try + { + // 0 + SchemaInstanceNamespace = dictionary.Add(Globals.SchemaInstanceNamespace); + SerializationNamespace = dictionary.Add(Globals.SerializationNamespace); + SchemaNamespace = dictionary.Add(Globals.SchemaNamespace); + XsiTypeLocalName = dictionary.Add(Globals.XsiTypeLocalName); + XsiNilLocalName = dictionary.Add(Globals.XsiNilLocalName); + + // 5 + IdLocalName = dictionary.Add(Globals.IdLocalName); + RefLocalName = dictionary.Add(Globals.RefLocalName); + ArraySizeLocalName = dictionary.Add(Globals.ArraySizeLocalName); + EmptyString = dictionary.Add(String.Empty); + ISerializableFactoryTypeLocalName = dictionary.Add(Globals.ISerializableFactoryTypeLocalName); + + // 10 + XmlnsNamespace = dictionary.Add(Globals.XmlnsNamespace); + CharLocalName = dictionary.Add("char"); + BooleanLocalName = dictionary.Add("boolean"); + SignedByteLocalName = dictionary.Add("byte"); + UnsignedByteLocalName = dictionary.Add("unsignedByte"); + + // 15 + ShortLocalName = dictionary.Add("short"); + UnsignedShortLocalName = dictionary.Add("unsignedShort"); + IntLocalName = dictionary.Add("int"); + UnsignedIntLocalName = dictionary.Add("unsignedInt"); + LongLocalName = dictionary.Add("long"); + + // 20 + UnsignedLongLocalName = dictionary.Add("unsignedLong"); + FloatLocalName = dictionary.Add("float"); + DoubleLocalName = dictionary.Add("double"); + DecimalLocalName = dictionary.Add("decimal"); + DateTimeLocalName = dictionary.Add("dateTime"); + + // 25 + StringLocalName = dictionary.Add("string"); + ByteArrayLocalName = dictionary.Add("base64Binary"); + ObjectLocalName = dictionary.Add("anyType"); + TimeSpanLocalName = dictionary.Add("duration"); + GuidLocalName = dictionary.Add("guid"); + + // 30 + UriLocalName = dictionary.Add("anyURI"); + QNameLocalName = dictionary.Add("QName"); + ClrTypeLocalName = dictionary.Add(Globals.ClrTypeLocalName); + ClrAssemblyLocalName = dictionary.Add(Globals.ClrAssemblyLocalName); + Space = dictionary.Add(Globals.Space); + + // 35 + timeLocalName = dictionary.Add("time"); + dateLocalName = dictionary.Add("date"); + hexBinaryLocalName = dictionary.Add("hexBinary"); + gYearMonthLocalName = dictionary.Add("gYearMonth"); + gYearLocalName = dictionary.Add("gYear"); + + // 40 + gMonthDayLocalName = dictionary.Add("gMonthDay"); + gDayLocalName = dictionary.Add("gDay"); + gMonthLocalName = dictionary.Add("gMonth"); + integerLocalName = dictionary.Add("integer"); + positiveIntegerLocalName = dictionary.Add("positiveInteger"); + + // 45 + negativeIntegerLocalName = dictionary.Add("negativeInteger"); + nonPositiveIntegerLocalName = dictionary.Add("nonPositiveInteger"); + nonNegativeIntegerLocalName = dictionary.Add("nonNegativeInteger"); + normalizedStringLocalName = dictionary.Add("normalizedString"); + tokenLocalName = dictionary.Add("token"); + + // 50 + languageLocalName = dictionary.Add("language"); + NameLocalName = dictionary.Add("Name"); + NCNameLocalName = dictionary.Add("NCName"); + XSDIDLocalName = dictionary.Add("ID"); + IDREFLocalName = dictionary.Add("IDREF"); + + // 55 + IDREFSLocalName = dictionary.Add("IDREFS"); + ENTITYLocalName = dictionary.Add("ENTITY"); + ENTITIESLocalName = dictionary.Add("ENTITIES"); + NMTOKENLocalName = dictionary.Add("NMTOKEN"); + NMTOKENSLocalName = dictionary.Add("NMTOKENS"); + + // 60 + AsmxTypesNamespace = dictionary.Add("http://microsoft.com/wsdl/types/"); + + // Add new templates here + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + } + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ElementData.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ElementData.cs new file mode 100644 index 0000000..b84b2d1 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ElementData.cs @@ -0,0 +1,53 @@ +using System; + +namespace Compat.Runtime.Serialization +{ + internal class AttributeData + { + public string prefix; + public string ns; + public string localName; + public string value; + } + + internal class ElementData + { + public string localName; + public string ns; + public string prefix; + public int attributeCount; + public AttributeData[] attributes; + public IDataNode dataNode; + public int childElementIndex; + + public void AddAttribute(string prefix, string ns, string name, string value) + { + GrowAttributesIfNeeded(); + AttributeData attribute = attributes[attributeCount]; + if (attribute == null) + { + attributes[attributeCount] = attribute = new AttributeData(); + } + + attribute.prefix = prefix; + attribute.ns = ns; + attribute.localName = name; + attribute.value = value; + attributeCount++; + } + + private void GrowAttributesIfNeeded() + { + if (attributes == null) + { + attributes = new AttributeData[4]; + } + else if (attributes.Length == attributeCount) + { + AttributeData[] newAttributes = new AttributeData[attributes.Length * 2]; + Array.Copy(attributes, 0, newAttributes, 0, attributes.Length); + attributes = newAttributes; + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/EnumDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/EnumDataContract.cs new file mode 100644 index 0000000..64fe99a --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/EnumDataContract.cs @@ -0,0 +1,508 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Security; +using System.Threading; +using System.Xml; +using DataContractAttribute = System.Runtime.Serialization.DataContractAttribute; +using EnumMemberAttribute = System.Runtime.Serialization.EnumMemberAttribute; + +namespace Compat.Runtime.Serialization +{ + internal sealed class EnumDataContract : DataContract + { + private readonly EnumDataContractCriticalHelper helper; + + internal EnumDataContract() + : base(new EnumDataContractCriticalHelper()) + { + helper = base.Helper as EnumDataContractCriticalHelper; + } + + internal EnumDataContract(Type type) + : base(new EnumDataContractCriticalHelper(type)) + { + helper = base.Helper as EnumDataContractCriticalHelper; + } + + internal static XmlQualifiedName GetBaseContractName(Type type) + { + return EnumDataContractCriticalHelper.GetBaseContractName(type); + } + + internal static Type GetBaseType(XmlQualifiedName baseContractName) + { + return EnumDataContractCriticalHelper.GetBaseType(baseContractName); + } + + internal XmlQualifiedName BaseContractName + { + get => helper.BaseContractName; + set => helper.BaseContractName = value; + } + + internal List Members + { + get => helper.Members; + set => helper.Members = value; + } + + internal List Values + { + get => helper.Values; + set => helper.Values = value; + } + + internal bool IsFlags + { + get => helper.IsFlags; + set => helper.IsFlags = value; + } + + internal bool IsULong + { + get => helper.IsULong; + } + + private XmlDictionaryString[] ChildElementNames + { + get => helper.ChildElementNames; + } + + internal override bool CanContainReferences => false; + + private class EnumDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private static readonly Dictionary typeToName; + private static readonly Dictionary nameToType; + private XmlQualifiedName baseContractName; + private List members; + private List values; + private bool isULong; + private bool isFlags; + private readonly bool hasDataContract; + private readonly XmlDictionaryString[] childElementNames; + + static EnumDataContractCriticalHelper() + { + typeToName = new Dictionary(); + nameToType = new Dictionary(); + Add(typeof(sbyte), "byte"); + Add(typeof(byte), "unsignedByte"); + Add(typeof(short), "short"); + Add(typeof(ushort), "unsignedShort"); + Add(typeof(int), "int"); + Add(typeof(uint), "unsignedInt"); + Add(typeof(long), "long"); + Add(typeof(ulong), "unsignedLong"); + } + + internal static void Add(Type type, string localName) + { + XmlQualifiedName stableName = CreateQualifiedName(localName, Globals.SchemaNamespace); + typeToName.Add(type, stableName); + nameToType.Add(stableName, type); + } + + internal static XmlQualifiedName GetBaseContractName(Type type) + { + typeToName.TryGetValue(type, out XmlQualifiedName retVal); + return retVal; + } + + internal static Type GetBaseType(XmlQualifiedName baseContractName) + { + nameToType.TryGetValue(baseContractName, out Type retVal); + return retVal; + } + + internal EnumDataContractCriticalHelper() + { + IsValueType = true; + } + + internal EnumDataContractCriticalHelper(Type type) + : base(type) + { + StableName = DataContract.GetStableName(type, out hasDataContract); + Type baseType = Enum.GetUnderlyingType(type); + baseContractName = GetBaseContractName(baseType); + ImportBaseType(baseType); + IsFlags = type.IsDefined(Globals.TypeOfFlagsAttribute, false); + ImportDataMembers(); + + XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); + childElementNames = new XmlDictionaryString[Members.Count]; + for (int i = 0; i < Members.Count; i++) + { + childElementNames[i] = dictionary.Add(Members[i].Name); + } + + if (TryGetDCAttribute(type, out DataContractAttribute dataContractAttribute)) + { + if (dataContractAttribute.IsReference) + { + DataContract.ThrowInvalidDataContractException( + SR.Format(SR.EnumTypeCannotHaveIsReference, + DataContract.GetClrTypeFullName(type), + dataContractAttribute.IsReference, + false), + type); + } + } + } + + internal XmlQualifiedName BaseContractName + { + get => baseContractName; + set + { + baseContractName = value; + Type baseType = GetBaseType(baseContractName); + if (baseType == null) + { + ThrowInvalidDataContractException(SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, StableName.Name, StableName.Namespace)); + } + + ImportBaseType(baseType); + } + } + + internal List Members + { + get => members; + set => members = value; + } + + internal List Values + { + get => values; + set => values = value; + } + + internal bool IsFlags + { + get => isFlags; + set => isFlags = value; + } + + internal bool IsULong => isULong; + + internal XmlDictionaryString[] ChildElementNames => childElementNames; + + private void ImportBaseType(Type baseType) + { + isULong = (baseType == Globals.TypeOfULong); + } + + private void ImportDataMembers() + { + Type type = UnderlyingType; + FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); + Dictionary memberValuesTable = new Dictionary(); + List tempMembers = new List(fields.Length); + List tempValues = new List(fields.Length); + + for (int i = 0; i < fields.Length; i++) + { + FieldInfo field = fields[i]; + bool enumMemberValid = false; + if (hasDataContract) + { + object[] memberAttributes = field.GetCustomAttributes(Globals.TypeOfEnumMemberAttribute, false); + if (memberAttributes != null && memberAttributes.Length > 0) + { + if (memberAttributes.Length > 1) + { + ThrowInvalidDataContractException(SR.Format(SR.TooManyEnumMembers, DataContract.GetClrTypeFullName(field.DeclaringType), field.Name)); + } + + EnumMemberAttribute memberAttribute = (EnumMemberAttribute)memberAttributes[0]; + + DataMember memberContract = new DataMember(field); + if (memberAttribute.IsValueSetExplicitly) + { + if (memberAttribute.Value == null || memberAttribute.Value.Length == 0) + { + ThrowInvalidDataContractException(SR.Format(SR.InvalidEnumMemberValue, field.Name, DataContract.GetClrTypeFullName(type))); + } + + memberContract.Name = memberAttribute.Value; + } + else + { + memberContract.Name = field.Name; + } + + ClassDataContract.CheckAndAddMember(tempMembers, memberContract, memberValuesTable); + enumMemberValid = true; + } + + object[] dataMemberAttributes = field.GetCustomAttributes(Globals.TypeOfDataMemberAttribute, false); + if (dataMemberAttributes != null && dataMemberAttributes.Length > 0) + { + ThrowInvalidDataContractException(SR.Format(SR.DataMemberOnEnumField, DataContract.GetClrTypeFullName(field.DeclaringType), field.Name)); + } + } + else + { + if (!field.IsNotSerialized) + { + DataMember memberContract = new DataMember(field) + { + Name = field.Name + }; + ClassDataContract.CheckAndAddMember(tempMembers, memberContract, memberValuesTable); + enumMemberValid = true; + } + } + + if (enumMemberValid) + { + object enumValue = field.GetValue(null); + if (isULong) + { + tempValues.Add((long)((IConvertible)enumValue).ToUInt64(null)); + } + else + { + tempValues.Add(((IConvertible)enumValue).ToInt64(null)); + } + } + } + + Thread.MemoryBarrier(); + members = tempMembers; + values = tempValues; + } + } + + internal void WriteEnumValue(XmlWriterDelegator writer, object value) + { + long longValue = IsULong ? (long)((IConvertible)value).ToUInt64(null) : ((IConvertible)value).ToInt64(null); + for (int i = 0; i < Values.Count; i++) + { + if (longValue == Values[i]) + { + writer.WriteString(ChildElementNames[i].Value); + return; + } + } + if (IsFlags) + { + int zeroIndex = -1; + bool noneWritten = true; + for (int i = 0; i < Values.Count; i++) + { + long current = Values[i]; + if (current == 0) + { + zeroIndex = i; + continue; + } + if (longValue == 0) + { + break; + } + + if ((current & longValue) == current) + { + if (noneWritten) + { + noneWritten = false; + } + else + { + writer.WriteString(DictionaryGlobals.Space.Value); + } + + writer.WriteString(ChildElementNames[i].Value); + longValue &= ~current; + } + } + // enforce that enum value was completely parsed + if (longValue != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidEnumValueOnWrite, value, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + if (noneWritten && zeroIndex >= 0) + { + writer.WriteString(ChildElementNames[zeroIndex].Value); + } + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidEnumValueOnWrite, value, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + } + + internal object ReadEnumValue(XmlReaderDelegator reader) + { + string stringValue = reader.ReadElementContentAsString(); + long longValue = 0; + int i = 0; + if (IsFlags) + { + // Skip initial spaces + for (; i < stringValue.Length; i++) + { + if (stringValue[i] != ' ') + { + break; + } + } + + // Read space-delimited values + int startIndex = i; + int count = 0; + for (; i < stringValue.Length; i++) + { + if (stringValue[i] == ' ') + { + count = i - startIndex; + if (count > 0) + { + longValue |= ReadEnumValue(stringValue, startIndex, count); + } + + for (++i; i < stringValue.Length; i++) + { + if (stringValue[i] != ' ') + { + break; + } + } + + startIndex = i; + if (i == stringValue.Length) + { + break; + } + } + } + count = i - startIndex; + if (count > 0) + { + longValue |= ReadEnumValue(stringValue, startIndex, count); + } + } + else + { + if (stringValue.Length == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidEnumValueOnRead, stringValue, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + longValue = ReadEnumValue(stringValue, 0, stringValue.Length); + } + + if (IsULong) + { + return Enum.ToObject(UnderlyingType, (ulong)longValue); + } + + return Enum.ToObject(UnderlyingType, longValue); + } + + private long ReadEnumValue(string value, int index, int count) + { + for (int i = 0; i < Members.Count; i++) + { + string memberName = Members[i].Name; + if (memberName.Length == count && string.CompareOrdinal(value, index, memberName, 0, count) == 0) + { + return Values[i]; + } + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.InvalidEnumValueOnRead, value.Substring(index, count), DataContract.GetClrTypeFullName(UnderlyingType)))); + } + + internal string GetStringFromEnumValue(long value) + { + if (IsULong) + { + return XmlConvert.ToString((ulong)value); + } + else + { + return XmlConvert.ToString(value); + } + } + + internal long GetEnumValueFromString(string value) + { + if (IsULong) + { + return (long)XmlConverter.ToUInt64(value); + } + else + { + return XmlConverter.ToInt64(value); + } + } + + internal override bool Equals(object other, Dictionary checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + { + return true; + } + + if (base.Equals(other, null)) + { + EnumDataContract dataContract = other as EnumDataContract; + if (dataContract != null) + { + if (Members.Count != dataContract.Members.Count || Values.Count != dataContract.Values.Count) + { + return false; + } + + string[] memberNames1 = new string[Members.Count], memberNames2 = new string[Members.Count]; + for (int i = 0; i < Members.Count; i++) + { + memberNames1[i] = Members[i].Name; + memberNames2[i] = dataContract.Members[i].Name; + } + Array.Sort(memberNames1); + Array.Sort(memberNames2); + for (int i = 0; i < Members.Count; i++) + { + if (memberNames1[i] != memberNames2[i]) + { + return false; + } + } + + return (IsFlags == dataContract.IsFlags); + } + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + WriteEnumValue(xmlWriter, obj); + } + + public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + { + object obj = ReadEnumValue(xmlReader); + if (context != null) + { + context.AddNewObject(obj); + } + + return obj; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ExportOptions.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExportOptions.cs new file mode 100644 index 0000000..986400f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExportOptions.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +using System; +using System.Collections.ObjectModel; + +namespace Compat.Runtime.Serialization +{ + public class ExportOptions + { + private Collection knownTypes; + private IDataContractSurrogate dataContractSurrogate; + + public IDataContractSurrogate DataContractSurrogate + { + get => dataContractSurrogate; + set => dataContractSurrogate = value; + } + + internal IDataContractSurrogate GetSurrogate() + { + return dataContractSurrogate; + } + + public Collection KnownTypes + { + get + { + if (knownTypes == null) + { + knownTypes = new Collection(); + } + return knownTypes; + } + } + } +} + diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataMember.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataMember.cs new file mode 100644 index 0000000..95c874a --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataMember.cs @@ -0,0 +1,13 @@ +namespace Compat.Runtime.Serialization +{ + internal class ExtensionDataMember + { + public string Name { get; set; } + + public string Namespace { get; set; } + + public IDataNode Value { get; set; } + + public int MemberIndex { get; set; } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataObject.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataObject.cs new file mode 100644 index 0000000..143339f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataObject.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + public sealed class ExtensionDataObject + { + internal ExtensionDataObject() + { + } + + internal IList Members { get; set; } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataReader.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataReader.cs new file mode 100644 index 0000000..db9e0f6 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ExtensionDataReader.cs @@ -0,0 +1,877 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; +using SerializationException = System.Runtime.Serialization.SerializationException; + +namespace Compat.Runtime.Serialization +{ + internal class ExtensionDataReader : XmlReader + { + private enum ExtensionDataNodeType + { + None, + Element, + EndElement, + Text, + Xml, + ReferencedElement, + NullElement, + } + + private readonly Hashtable cache = new Hashtable(); + private ElementData[] elements; + private ElementData element; + private ElementData nextElement; + private ReadState readState = ReadState.Initial; + private ExtensionDataNodeType internalNodeType; + private XmlNodeType nodeType; + private int depth; + private string localName; + private string ns; + private string prefix; + private string value; + private int attributeCount; + private int attributeIndex; + private XmlNodeReader xmlNodeReader; + private Queue deserializedDataNodes; + private readonly XmlObjectSerializerReadContext context; + + private static readonly Dictionary nsToPrefixTable; + + private static readonly Dictionary prefixToNsTable; + + static ExtensionDataReader() + { + nsToPrefixTable = new Dictionary(); + prefixToNsTable = new Dictionary(); + AddPrefix(Globals.XsiPrefix, Globals.SchemaInstanceNamespace); + AddPrefix(Globals.SerPrefix, Globals.SerializationNamespace); + AddPrefix(string.Empty, string.Empty); + } + + internal ExtensionDataReader(XmlObjectSerializerReadContext context) + { + attributeIndex = -1; + this.context = context; + } + + internal void SetDeserializedValue(object obj) + { + IDataNode deserializedDataNode = (deserializedDataNodes == null || deserializedDataNodes.Count == 0) ? null : deserializedDataNodes.Dequeue(); + if (deserializedDataNode != null && !(obj is IDataNode)) + { + deserializedDataNode.Value = obj; + deserializedDataNode.IsFinalValue = true; + } + } + + internal IDataNode GetCurrentNode() + { + IDataNode retVal = element.dataNode; + Skip(); + return retVal; + } + + internal void SetDataNode(IDataNode dataNode, string name, string ns) + { + SetNextElement(dataNode, name, ns, null); + element = nextElement; + nextElement = null; + SetElement(); + } + + internal void Reset() + { + localName = null; + ns = null; + prefix = null; + value = null; + attributeCount = 0; + attributeIndex = -1; + depth = 0; + element = null; + nextElement = null; + elements = null; + deserializedDataNodes = null; + } + + private bool IsXmlDataNode => (internalNodeType == ExtensionDataNodeType.Xml); + + public override XmlNodeType NodeType => IsXmlDataNode ? xmlNodeReader.NodeType : nodeType; + public override string LocalName => IsXmlDataNode ? xmlNodeReader.LocalName : localName; + public override string NamespaceURI => IsXmlDataNode ? xmlNodeReader.NamespaceURI : ns; + public override string Prefix => IsXmlDataNode ? xmlNodeReader.Prefix : prefix; + public override string Value => IsXmlDataNode ? xmlNodeReader.Value : value; + public override int Depth => IsXmlDataNode ? xmlNodeReader.Depth : depth; + public override int AttributeCount => IsXmlDataNode ? xmlNodeReader.AttributeCount : attributeCount; + public override bool EOF => IsXmlDataNode ? xmlNodeReader.EOF : (readState == ReadState.EndOfFile); + public override ReadState ReadState => IsXmlDataNode ? xmlNodeReader.ReadState : readState; + public override bool IsEmptyElement => IsXmlDataNode ? xmlNodeReader.IsEmptyElement : false; + public override bool IsDefault => IsXmlDataNode ? xmlNodeReader.IsDefault : base.IsDefault; + public override char QuoteChar => IsXmlDataNode ? xmlNodeReader.QuoteChar : base.QuoteChar; + public override XmlSpace XmlSpace => IsXmlDataNode ? xmlNodeReader.XmlSpace : base.XmlSpace; + public override string XmlLang => IsXmlDataNode ? xmlNodeReader.XmlLang : base.XmlLang; + public override string this[int i] => IsXmlDataNode ? xmlNodeReader[i] : GetAttribute(i); + public override string this[string name] => IsXmlDataNode ? xmlNodeReader[name] : GetAttribute(name); + public override string this[string name, string namespaceURI] => IsXmlDataNode ? xmlNodeReader[name, namespaceURI] : GetAttribute(name, namespaceURI); + + public override bool MoveToFirstAttribute() + { + if (IsXmlDataNode) + { + return xmlNodeReader.MoveToFirstAttribute(); + } + + if (attributeCount == 0) + { + return false; + } + + MoveToAttribute(0); + return true; + } + + public override bool MoveToNextAttribute() + { + if (IsXmlDataNode) + { + return xmlNodeReader.MoveToNextAttribute(); + } + + if (attributeIndex + 1 >= attributeCount) + { + return false; + } + + MoveToAttribute(attributeIndex + 1); + return true; + } + + public override void MoveToAttribute(int index) + { + if (IsXmlDataNode) + { + xmlNodeReader.MoveToAttribute(index); + } + else + { + if (index < 0 || index >= attributeCount) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.InvalidXmlDeserializingExtensionData)); + } + + nodeType = XmlNodeType.Attribute; + AttributeData attribute = element.attributes[index]; + localName = attribute.localName; + ns = attribute.ns; + prefix = attribute.prefix; + value = attribute.value; + attributeIndex = index; + } + } + + public override string GetAttribute(string name, string namespaceURI) + { + if (IsXmlDataNode) + { + return xmlNodeReader.GetAttribute(name, namespaceURI); + } + + for (int i = 0; i < element.attributeCount; i++) + { + AttributeData attribute = element.attributes[i]; + if (attribute.localName == name && attribute.ns == namespaceURI) + { + return attribute.value; + } + } + + return null; + } + + public override bool MoveToAttribute(string name, string namespaceURI) + { + if (IsXmlDataNode) + { + return xmlNodeReader.MoveToAttribute(name, ns); + } + + for (int i = 0; i < element.attributeCount; i++) + { + AttributeData attribute = element.attributes[i]; + if (attribute.localName == name && attribute.ns == namespaceURI) + { + MoveToAttribute(i); + return true; + } + } + + return false; + } + + public override bool MoveToElement() + { + if (IsXmlDataNode) + { + return xmlNodeReader.MoveToElement(); + } + + if (nodeType != XmlNodeType.Attribute) + { + return false; + } + + SetElement(); + return true; + } + + private void SetElement() + { + nodeType = XmlNodeType.Element; + localName = element.localName; + ns = element.ns; + prefix = element.prefix; + value = string.Empty; + attributeCount = element.attributeCount; + attributeIndex = -1; + } + + public override string LookupNamespace(string prefix) + { + if (IsXmlDataNode) + { + return xmlNodeReader.LookupNamespace(prefix); + } + + if (!prefixToNsTable.TryGetValue(prefix, out string ns)) + { + return null; + } + + return ns; + } + + public override void Skip() + { + if (IsXmlDataNode) + { + xmlNodeReader.Skip(); + } + else + { + if (ReadState != ReadState.Interactive) + { + return; + } + + MoveToElement(); + if (IsElementNode(internalNodeType)) + { + int depth = 1; + while (depth != 0) + { + if (!Read()) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.InvalidXmlDeserializingExtensionData)); + } + + if (IsElementNode(internalNodeType)) + { + depth++; + } + else if (internalNodeType == ExtensionDataNodeType.EndElement) + { + ReadEndElement(); + depth--; + } + } + } + else + { + Read(); + } + } + } + + private bool IsElementNode(ExtensionDataNodeType nodeType) + { + return (nodeType == ExtensionDataNodeType.Element || + nodeType == ExtensionDataNodeType.ReferencedElement || + nodeType == ExtensionDataNodeType.NullElement); + } + + public override void Close() + { + if (IsXmlDataNode) + { + xmlNodeReader.Close(); + } + else + { + Reset(); + readState = ReadState.Closed; + } + } + + public override bool Read() + { + if (nodeType == XmlNodeType.Attribute && MoveToNextAttribute()) + { + return true; + } + + MoveNext(element.dataNode); + + switch (internalNodeType) + { + case ExtensionDataNodeType.Element: + case ExtensionDataNodeType.ReferencedElement: + case ExtensionDataNodeType.NullElement: + PushElement(); + SetElement(); + break; + + case ExtensionDataNodeType.Text: + nodeType = XmlNodeType.Text; + prefix = string.Empty; + ns = string.Empty; + localName = string.Empty; + attributeCount = 0; + attributeIndex = -1; + break; + + case ExtensionDataNodeType.EndElement: + nodeType = XmlNodeType.EndElement; + prefix = string.Empty; + ns = string.Empty; + localName = string.Empty; + value = string.Empty; + attributeCount = 0; + attributeIndex = -1; + PopElement(); + break; + + case ExtensionDataNodeType.None: + if (depth != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.InvalidXmlDeserializingExtensionData)); + } + + nodeType = XmlNodeType.None; + prefix = string.Empty; + ns = string.Empty; + localName = string.Empty; + value = string.Empty; + attributeCount = 0; + readState = ReadState.EndOfFile; + return false; + + case ExtensionDataNodeType.Xml: + // do nothing + break; + + default: + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.InvalidStateInExtensionDataReader)); + } + readState = ReadState.Interactive; + return true; + } + + public override string Name + { + get + { + if (IsXmlDataNode) + { + return xmlNodeReader.Name; + } + Fx.Assert("ExtensionDataReader Name property should only be called for IXmlSerializable"); + return string.Empty; + } + } + + public override bool HasValue + { + get + { + if (IsXmlDataNode) + { + return xmlNodeReader.HasValue; + } + Fx.Assert("ExtensionDataReader HasValue property should only be called for IXmlSerializable"); + return false; + } + } + + public override string BaseURI + { + get + { + if (IsXmlDataNode) + { + return xmlNodeReader.BaseURI; + } + Fx.Assert("ExtensionDataReader BaseURI property should only be called for IXmlSerializable"); + return string.Empty; + } + } + + public override XmlNameTable NameTable + { + get + { + if (IsXmlDataNode) + { + return xmlNodeReader.NameTable; + } + Fx.Assert("ExtensionDataReader NameTable property should only be called for IXmlSerializable"); + return null; + } + } + + public override string GetAttribute(string name) + { + if (IsXmlDataNode) + { + return xmlNodeReader.GetAttribute(name); + } + Fx.Assert("ExtensionDataReader GetAttribute method should only be called for IXmlSerializable"); + return null; + } + + public override string GetAttribute(int i) + { + if (IsXmlDataNode) + { + return xmlNodeReader.GetAttribute(i); + } + Fx.Assert("ExtensionDataReader GetAttribute method should only be called for IXmlSerializable"); + return null; + } + + public override bool MoveToAttribute(string name) + { + if (IsXmlDataNode) + { + return xmlNodeReader.MoveToAttribute(name); + } + Fx.Assert("ExtensionDataReader MoveToAttribute method should only be called for IXmlSerializable"); + return false; + } + + public override void ResolveEntity() + { + if (IsXmlDataNode) + { + xmlNodeReader.ResolveEntity(); + } + else + { + Fx.Assert("ExtensionDataReader ResolveEntity method should only be called for IXmlSerializable"); + } + } + + public override bool ReadAttributeValue() + { + if (IsXmlDataNode) + { + return xmlNodeReader.ReadAttributeValue(); + } + Fx.Assert("ExtensionDataReader ReadAttributeValue method should only be called for IXmlSerializable"); + return false; + } + + private void MoveNext(IDataNode dataNode) + { + switch (internalNodeType) + { + case ExtensionDataNodeType.Text: + case ExtensionDataNodeType.ReferencedElement: + case ExtensionDataNodeType.NullElement: + internalNodeType = ExtensionDataNodeType.EndElement; + return; + default: + Type dataNodeType = dataNode.DataType; + if (dataNodeType == Globals.TypeOfClassDataNode) + { + MoveNextInClass((ClassDataNode)dataNode); + } + else if (dataNodeType == Globals.TypeOfCollectionDataNode) + { + MoveNextInCollection((CollectionDataNode)dataNode); + } + else if (dataNodeType == Globals.TypeOfISerializableDataNode) + { + MoveNextInISerializable((ISerializableDataNode)dataNode); + } + else if (dataNodeType == Globals.TypeOfXmlDataNode) + { + MoveNextInXml((XmlDataNode)dataNode); + } + else if (dataNode.Value != null) + { + MoveToDeserializedObject(dataNode); + } + else + { + Fx.Assert("Encountered invalid data node when deserializing unknown data"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.InvalidStateInExtensionDataReader)); + } + break; + } + } + + private void SetNextElement(IDataNode node, string name, string ns, string prefix) + { + internalNodeType = ExtensionDataNodeType.Element; + nextElement = GetNextElement(); + nextElement.localName = name; + nextElement.ns = ns; + nextElement.prefix = prefix; + if (node == null) + { + nextElement.attributeCount = 0; + nextElement.AddAttribute(Globals.XsiPrefix, Globals.SchemaInstanceNamespace, Globals.XsiNilLocalName, Globals.True); + internalNodeType = ExtensionDataNodeType.NullElement; + } + else if (!CheckIfNodeHandled(node)) + { + AddDeserializedDataNode(node); + node.GetData(nextElement); + if (node is XmlDataNode) + { + MoveNextInXml((XmlDataNode)node); + } + } + } + + private void AddDeserializedDataNode(IDataNode node) + { + if (node.Id != Globals.NewObjectId && (node.Value == null || !node.IsFinalValue)) + { + if (deserializedDataNodes == null) + { + deserializedDataNodes = new Queue(); + } + + deserializedDataNodes.Enqueue(node); + } + } + + private bool CheckIfNodeHandled(IDataNode node) + { + bool handled = false; + if (node.Id != Globals.NewObjectId) + { + handled = (cache[node] != null); + if (handled) + { + if (nextElement == null) + { + nextElement = GetNextElement(); + } + + nextElement.attributeCount = 0; + nextElement.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.RefLocalName, node.Id.ToString(NumberFormatInfo.InvariantInfo)); + nextElement.AddAttribute(Globals.XsiPrefix, Globals.SchemaInstanceNamespace, Globals.XsiNilLocalName, Globals.True); + internalNodeType = ExtensionDataNodeType.ReferencedElement; + } + else + { + cache.Add(node, node); + } + } + return handled; + } + + private void MoveNextInClass(ClassDataNode dataNode) + { + if (dataNode.Members != null && element.childElementIndex < dataNode.Members.Count) + { + if (element.childElementIndex == 0) + { + context.IncrementItemCount(-dataNode.Members.Count); + } + + ExtensionDataMember member = dataNode.Members[element.childElementIndex++]; + SetNextElement(member.Value, member.Name, member.Namespace, GetPrefix(member.Namespace)); + } + else + { + internalNodeType = ExtensionDataNodeType.EndElement; + element.childElementIndex = 0; + } + } + + private void MoveNextInCollection(CollectionDataNode dataNode) + { + if (dataNode.Items != null && element.childElementIndex < dataNode.Items.Count) + { + if (element.childElementIndex == 0) + { + context.IncrementItemCount(-dataNode.Items.Count); + } + + IDataNode item = dataNode.Items[element.childElementIndex++]; + SetNextElement(item, dataNode.ItemName, dataNode.ItemNamespace, GetPrefix(dataNode.ItemNamespace)); + } + else + { + internalNodeType = ExtensionDataNodeType.EndElement; + element.childElementIndex = 0; + } + } + + private void MoveNextInISerializable(ISerializableDataNode dataNode) + { + if (dataNode.Members != null && element.childElementIndex < dataNode.Members.Count) + { + if (element.childElementIndex == 0) + { + context.IncrementItemCount(-dataNode.Members.Count); + } + + ISerializableDataMember member = dataNode.Members[element.childElementIndex++]; + SetNextElement(member.Value, member.Name, string.Empty, string.Empty); + } + else + { + internalNodeType = ExtensionDataNodeType.EndElement; + element.childElementIndex = 0; + } + } + + private void MoveNextInXml(XmlDataNode dataNode) + { + if (IsXmlDataNode) + { + xmlNodeReader.Read(); + if (xmlNodeReader.Depth == 0) + { + internalNodeType = ExtensionDataNodeType.EndElement; + xmlNodeReader = null; + } + } + else + { + internalNodeType = ExtensionDataNodeType.Xml; + if (element == null) + { + element = nextElement; + } + else + { + PushElement(); + } + + XmlNode wrapperElement = XmlObjectSerializerReadContext.CreateWrapperXmlElement(dataNode.OwnerDocument, + dataNode.XmlAttributes, dataNode.XmlChildNodes, element.prefix, element.localName, element.ns); + for (int i = 0; i < element.attributeCount; i++) + { + AttributeData a = element.attributes[i]; + XmlAttribute xmlAttr = dataNode.OwnerDocument.CreateAttribute(a.prefix, a.localName, a.ns); + xmlAttr.Value = a.value; + wrapperElement.Attributes.Append(xmlAttr); + } + xmlNodeReader = new XmlNodeReader(wrapperElement); + xmlNodeReader.Read(); + } + } + + private void MoveToDeserializedObject(IDataNode dataNode) + { + Type type = dataNode.DataType; + bool isTypedNode = true; + if (type == Globals.TypeOfObject) + { + type = dataNode.Value.GetType(); + if (type == Globals.TypeOfObject) + { + internalNodeType = ExtensionDataNodeType.EndElement; + return; + } + isTypedNode = false; + } + + if (!MoveToText(type, dataNode, isTypedNode)) + { + if (dataNode.IsFinalValue) + { + internalNodeType = ExtensionDataNodeType.EndElement; + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.InvalidDataNode, DataContract.GetClrTypeFullName(type)))); + } + } + } + + private bool MoveToText(Type type, IDataNode dataNode, bool isTypedNode) + { + bool handled = true; + switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (bool)dataNode.Value); + break; + case TypeCode.Char: + value = XmlConvert.ToString((int)(isTypedNode ? ((DataNode)dataNode).GetValue() : (char)dataNode.Value)); + break; + case TypeCode.Byte: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (byte)dataNode.Value); + break; + case TypeCode.Int16: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (short)dataNode.Value); + break; + case TypeCode.Int32: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (int)dataNode.Value); + break; + case TypeCode.Int64: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (long)dataNode.Value); + break; + case TypeCode.Single: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (float)dataNode.Value); + break; + case TypeCode.Double: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (double)dataNode.Value); + break; + case TypeCode.Decimal: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (decimal)dataNode.Value); + break; + case TypeCode.DateTime: + DateTime dateTime = isTypedNode ? ((DataNode)dataNode).GetValue() : (DateTime)dataNode.Value; + value = dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", DateTimeFormatInfo.InvariantInfo); + break; + case TypeCode.String: + value = isTypedNode ? ((DataNode)dataNode).GetValue() : (string)dataNode.Value; + break; + case TypeCode.SByte: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (sbyte)dataNode.Value); + break; + case TypeCode.UInt16: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (ushort)dataNode.Value); + break; + case TypeCode.UInt32: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (uint)dataNode.Value); + break; + case TypeCode.UInt64: + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (ulong)dataNode.Value); + break; + case TypeCode.Object: + default: + if (type == Globals.TypeOfByteArray) + { + byte[] bytes = isTypedNode ? ((DataNode)dataNode).GetValue() : (byte[])dataNode.Value; + value = (bytes == null) ? string.Empty : Convert.ToBase64String(bytes); + } + else if (type == Globals.TypeOfTimeSpan) + { + value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (TimeSpan)dataNode.Value); + } + else if (type == Globals.TypeOfGuid) + { + Guid guid = isTypedNode ? ((DataNode)dataNode).GetValue() : (Guid)dataNode.Value; + value = guid.ToString(); + } + else if (type == Globals.TypeOfUri) + { + Uri uri = isTypedNode ? ((DataNode)dataNode).GetValue() : (Uri)dataNode.Value; + value = uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped); + } + else + { + handled = false; + } + + break; + } + + if (handled) + { + internalNodeType = ExtensionDataNodeType.Text; + } + + return handled; + } + + private void PushElement() + { + GrowElementsIfNeeded(); + elements[depth++] = element; + if (nextElement == null) + { + element = GetNextElement(); + } + else + { + element = nextElement; + nextElement = null; + } + } + + private void PopElement() + { + prefix = element.prefix; + localName = element.localName; + ns = element.ns; + + if (depth == 0) + { + return; + } + + depth--; + + if (elements != null) + { + element = elements[depth]; + } + } + + private void GrowElementsIfNeeded() + { + if (elements == null) + { + elements = new ElementData[8]; + } + else if (elements.Length == depth) + { + ElementData[] newElements = new ElementData[elements.Length * 2]; + Array.Copy(elements, 0, newElements, 0, elements.Length); + elements = newElements; + } + } + + private ElementData GetNextElement() + { + int nextDepth = depth + 1; + return (elements == null || elements.Length <= nextDepth || elements[nextDepth] == null) + ? new ElementData() : elements[nextDepth]; + } + + internal static string GetPrefix(string ns) + { + ns = ns ?? string.Empty; + if (!nsToPrefixTable.TryGetValue(ns, out string prefix)) + { + lock (nsToPrefixTable) + { + if (!nsToPrefixTable.TryGetValue(ns, out prefix)) + { + prefix = (ns == null || ns.Length == 0) ? string.Empty : "p" + nsToPrefixTable.Count; + AddPrefix(prefix, ns); + } + } + } + return prefix; + } + + private static void AddPrefix(string prefix, string ns) + { + nsToPrefixTable.Add(ns, prefix); + prefixToNsTable.Add(prefix, ns); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericInfo.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericInfo.cs new file mode 100644 index 0000000..1859ebb --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericInfo.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal class GenericInfo : IGenericNameProvider + { + private readonly string genericTypeName; + private readonly XmlQualifiedName stableName; + private List paramGenericInfos; + private readonly List nestedParamCounts; + + internal GenericInfo(XmlQualifiedName stableName, string genericTypeName) + { + this.stableName = stableName; + this.genericTypeName = genericTypeName; + nestedParamCounts = new List + { + 0 + }; + } + + internal void Add(GenericInfo actualParamInfo) + { + if (paramGenericInfos == null) + { + paramGenericInfos = new List(); + } + + paramGenericInfos.Add(actualParamInfo); + } + + internal void AddToLevel(int level, int count) + { + if (level >= nestedParamCounts.Count) + { + do + { + nestedParamCounts.Add((level == nestedParamCounts.Count) ? count : 0); + } while (level >= nestedParamCounts.Count); + } + else + { + nestedParamCounts[level] = nestedParamCounts[level] + count; + } + } + + internal XmlQualifiedName GetExpandedStableName() + { + if (paramGenericInfos == null) + { + return stableName; + } + + return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), this)), stableName.Namespace); + } + + internal string GetStableNamespace() + { + return stableName.Namespace; + } + + internal XmlQualifiedName StableName => stableName; + + internal IList Parameters => paramGenericInfos; + + public int GetParameterCount() + { + return paramGenericInfos.Count; + } + + public IList GetNestedParameterCounts() + { + return nestedParamCounts; + } + + public string GetParameterName(int paramIndex) + { + return paramGenericInfos[paramIndex].GetExpandedStableName().Name; + } + + public string GetNamespaces() + { + StringBuilder namespaces = new StringBuilder(); + for (int j = 0; j < paramGenericInfos.Count; j++) + { + namespaces.Append(" ").Append(paramGenericInfos[j].GetStableNamespace()); + } + + return namespaces.ToString(); + } + + public string GetGenericTypeName() + { + return genericTypeName; + } + + public bool ParametersFromBuiltInNamespaces + { + get + { + bool parametersFromBuiltInNamespaces = true; + for (int j = 0; j < paramGenericInfos.Count; j++) + { + if (parametersFromBuiltInNamespaces) + { + parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(paramGenericInfos[j].GetStableNamespace()); + } + else + { + break; + } + } + return parametersFromBuiltInNamespaces; + } + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericNameProvider.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericNameProvider.cs new file mode 100644 index 0000000..86043cd --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericNameProvider.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal interface IGenericNameProvider + { + int GetParameterCount(); + IList GetNestedParameterCounts(); + string GetParameterName(int paramIndex); + string GetNamespaces(); + string GetGenericTypeName(); + bool ParametersFromBuiltInNamespaces { get; } + } + + internal class GenericNameProvider : IGenericNameProvider + { + private readonly string _genericTypeName; + private readonly object[] _genericParams; //Type or DataContract + private readonly IList _nestedParamCounts; + + internal GenericNameProvider(Type type) + : this(DataContract.GetClrTypeFullName(type.GetGenericTypeDefinition()), type.GetGenericArguments()) + { + } + + internal GenericNameProvider(string genericTypeName, object[] genericParams) + { + _genericTypeName = genericTypeName; + _genericParams = new object[genericParams.Length]; + genericParams.CopyTo(_genericParams, 0); + + DataContract.GetClrNameAndNamespace(genericTypeName, out string name, out string ns); + _nestedParamCounts = DataContract.GetDataContractNameForGenericName(name, null); + } + + public int GetParameterCount() + { + return _genericParams.Length; + } + + public IList GetNestedParameterCounts() + { + return _nestedParamCounts; + } + + public string GetParameterName(int paramIndex) + { + return GetStableName(paramIndex).Name; + } + + public string GetNamespaces() + { + StringBuilder namespaces = new StringBuilder(); + for (int j = 0; j < GetParameterCount(); j++) + { + namespaces.Append(" ").Append(GetStableName(j).Namespace); + } + + return namespaces.ToString(); + } + + public string GetGenericTypeName() + { + return _genericTypeName; + } + + public bool ParametersFromBuiltInNamespaces + { + get + { + bool parametersFromBuiltInNamespaces = true; + for (int j = 0; j < GetParameterCount(); j++) + { + if (parametersFromBuiltInNamespaces) + { + parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(GetStableName(j).Namespace); + } + else + { + break; + } + } + return parametersFromBuiltInNamespaces; + } + } + + private XmlQualifiedName GetStableName(int i) + { + object o = _genericParams[i]; + XmlQualifiedName qname = o as XmlQualifiedName; + if (qname == null) + { + Type paramType = o as Type; + if (paramType != null) + { + _genericParams[i] = qname = DataContract.GetStableName(paramType); + } + else + { + _genericParams[i] = qname = ((DataContract)o).StableName; + } + } + return qname; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericParameterDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericParameterDataContract.cs new file mode 100644 index 0000000..11bb915 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/GenericParameterDataContract.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + internal sealed class GenericParameterDataContract : DataContract + { + private readonly GenericParameterDataContractCriticalHelper _helper; + + internal GenericParameterDataContract(Type type) + : base(new GenericParameterDataContractCriticalHelper(type)) + { + _helper = base.Helper as GenericParameterDataContractCriticalHelper; + } + + internal int ParameterPosition => _helper.ParameterPosition; + + internal override bool IsBuiltInDataContract => true; + + private class GenericParameterDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private readonly int parameterPosition; + + internal GenericParameterDataContractCriticalHelper(Type type) + : base(type) + { + SetDataContractName(DataContract.GetStableName(type)); + parameterPosition = type.GenericParameterPosition; + } + + internal int ParameterPosition => parameterPosition; + } + + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + return paramContracts[ParameterPosition]; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/Globals.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/Globals.cs new file mode 100644 index 0000000..564cc2a --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/Globals.cs @@ -0,0 +1,1445 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace Compat.Runtime.Serialization +{ + internal static class Globals + { + internal const BindingFlags ScanAllMembers = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; + + private static XmlQualifiedName idQualifiedName; + internal static XmlQualifiedName IdQualifiedName + { + + get + { + if (idQualifiedName == null) + { + idQualifiedName = new XmlQualifiedName(Globals.IdLocalName, Globals.SerializationNamespace); + } + + return idQualifiedName; + } + } + + private static XmlQualifiedName refQualifiedName; + internal static XmlQualifiedName RefQualifiedName + { + get + { + if (refQualifiedName == null) + { + refQualifiedName = new XmlQualifiedName(Globals.RefLocalName, Globals.SerializationNamespace); + } + + return refQualifiedName; + } + } + + private static Type typeOfObject; + internal static Type TypeOfObject + { + get + { + if (typeOfObject == null) + { + typeOfObject = typeof(object); + } + + return typeOfObject; + } + } + + private static Type typeOfValueType; + internal static Type TypeOfValueType + { + get + { + if (typeOfValueType == null) + { + typeOfValueType = typeof(ValueType); + } + + return typeOfValueType; + } + } + + private static Type typeOfArray; + internal static Type TypeOfArray + { + get + { + if (typeOfArray == null) + { + typeOfArray = typeof(Array); + } + + return typeOfArray; + } + } + + private static Type typeOfString; + internal static Type TypeOfString + { + get + { + if (typeOfString == null) + { + typeOfString = typeof(string); + } + + return typeOfString; + } + } + + private static Type typeOfInt; + internal static Type TypeOfInt + { + get + { + if (typeOfInt == null) + { + typeOfInt = typeof(int); + } + + return typeOfInt; + } + } + + private static Type typeOfULong; + internal static Type TypeOfULong + { + get + { + if (typeOfULong == null) + { + typeOfULong = typeof(ulong); + } + + return typeOfULong; + } + } + + private static Type typeOfVoid; + internal static Type TypeOfVoid + { + get + { + if (typeOfVoid == null) + { + typeOfVoid = typeof(void); + } + + return typeOfVoid; + } + } + + private static Type typeOfByteArray; + internal static Type TypeOfByteArray + { + get + { + if (typeOfByteArray == null) + { + typeOfByteArray = typeof(byte[]); + } + + return typeOfByteArray; + } + } + + private static Type typeOfTimeSpan; + internal static Type TypeOfTimeSpan + { + get + { + if (typeOfTimeSpan == null) + { + typeOfTimeSpan = typeof(TimeSpan); + } + + return typeOfTimeSpan; + } + } + + private static Type typeOfGuid; + internal static Type TypeOfGuid + { + get + { + if (typeOfGuid == null) + { + typeOfGuid = typeof(Guid); + } + + return typeOfGuid; + } + } + + private static Type typeOfDateTimeOffset; + internal static Type TypeOfDateTimeOffset + { + get + { + if (typeOfDateTimeOffset == null) + { + typeOfDateTimeOffset = typeof(DateTimeOffset); + } + + return typeOfDateTimeOffset; + } + } + + private static Type typeOfDateTimeOffsetAdapter; + internal static Type TypeOfDateTimeOffsetAdapter + { + get + { + if (typeOfDateTimeOffsetAdapter == null) + { + typeOfDateTimeOffsetAdapter = typeof(DateTimeOffsetAdapter); + } + + return typeOfDateTimeOffsetAdapter; + } + } + + private static Type typeOfUri; + internal static Type TypeOfUri + { + get + { + if (typeOfUri == null) + { + typeOfUri = typeof(Uri); + } + + return typeOfUri; + } + } + + private static Type typeOfTypeEnumerable; + internal static Type TypeOfTypeEnumerable + { + get + { + if (typeOfTypeEnumerable == null) + { + typeOfTypeEnumerable = typeof(IEnumerable); + } + + return typeOfTypeEnumerable; + } + } + + private static Type typeOfStreamingContext; + internal static Type TypeOfStreamingContext + { + get + { + if (typeOfStreamingContext == null) + { + typeOfStreamingContext = typeof(System.Runtime.Serialization.StreamingContext); + } + + return typeOfStreamingContext; + } + } + + private static Type typeOfISerializable; + internal static Type TypeOfISerializable + { + get + { + if (typeOfISerializable == null) + { + typeOfISerializable = typeof(System.Runtime.Serialization.ISerializable); + } + + return typeOfISerializable; + } + } + + private static Type typeOfIDeserializationCallback; + internal static Type TypeOfIDeserializationCallback + { + get + { + if (typeOfIDeserializationCallback == null) + { + typeOfIDeserializationCallback = typeof(System.Runtime.Serialization.IDeserializationCallback); + } + + return typeOfIDeserializationCallback; + } + } + + private static Type typeOfIObjectReference; + internal static Type TypeOfIObjectReference + { + get + { + if (typeOfIObjectReference == null) + { + typeOfIObjectReference = typeof(System.Runtime.Serialization.IObjectReference); + } + + return typeOfIObjectReference; + } + } + + private static Type typeOfXmlFormatClassWriterDelegate; + internal static Type TypeOfXmlFormatClassWriterDelegate + { + get + { + if (typeOfXmlFormatClassWriterDelegate == null) + { + typeOfXmlFormatClassWriterDelegate = typeof(XmlFormatClassWriterDelegate); + } + + return typeOfXmlFormatClassWriterDelegate; + } + } + + private static Type typeOfXmlFormatCollectionWriterDelegate; + internal static Type TypeOfXmlFormatCollectionWriterDelegate + { + get + { + if (typeOfXmlFormatCollectionWriterDelegate == null) + { + typeOfXmlFormatCollectionWriterDelegate = typeof(XmlFormatCollectionWriterDelegate); + } + + return typeOfXmlFormatCollectionWriterDelegate; + } + } + + private static Type typeOfXmlFormatClassReaderDelegate; + internal static Type TypeOfXmlFormatClassReaderDelegate + { + get + { + if (typeOfXmlFormatClassReaderDelegate == null) + { + typeOfXmlFormatClassReaderDelegate = typeof(XmlFormatClassReaderDelegate); + } + + return typeOfXmlFormatClassReaderDelegate; + } + } + + + private static Type typeOfXmlFormatCollectionReaderDelegate; + internal static Type TypeOfXmlFormatCollectionReaderDelegate + { + get + { + if (typeOfXmlFormatCollectionReaderDelegate == null) + { + typeOfXmlFormatCollectionReaderDelegate = typeof(XmlFormatCollectionReaderDelegate); + } + + return typeOfXmlFormatCollectionReaderDelegate; + } + } + + + private static Type typeOfXmlFormatGetOnlyCollectionReaderDelegate; + internal static Type TypeOfXmlFormatGetOnlyCollectionReaderDelegate + { + + get + { + if (typeOfXmlFormatGetOnlyCollectionReaderDelegate == null) + { + typeOfXmlFormatGetOnlyCollectionReaderDelegate = typeof(XmlFormatGetOnlyCollectionReaderDelegate); + } + + return typeOfXmlFormatGetOnlyCollectionReaderDelegate; + } + } + + + private static Type typeOfKnownTypeAttribute; + internal static Type TypeOfKnownTypeAttribute + { + + get + { + if (typeOfKnownTypeAttribute == null) + { + typeOfKnownTypeAttribute = typeof(System.Runtime.Serialization.KnownTypeAttribute); + } + + return typeOfKnownTypeAttribute; + } + } + + + private static Type typeOfDataContractAttribute; + internal static Type TypeOfDataContractAttribute + { + + get + { + if (typeOfDataContractAttribute == null) + { + typeOfDataContractAttribute = typeof(System.Runtime.Serialization.DataContractAttribute); + } + + return typeOfDataContractAttribute; + } + } + + + private static Type typeOfContractNamespaceAttribute; + internal static Type TypeOfContractNamespaceAttribute + { + + get + { + if (typeOfContractNamespaceAttribute == null) + { + typeOfContractNamespaceAttribute = typeof(System.Runtime.Serialization.ContractNamespaceAttribute); + } + + return typeOfContractNamespaceAttribute; + } + } + + + private static Type typeOfDataMemberAttribute; + internal static Type TypeOfDataMemberAttribute + { + + get + { + if (typeOfDataMemberAttribute == null) + { + typeOfDataMemberAttribute = typeof(System.Runtime.Serialization.DataMemberAttribute); + } + + return typeOfDataMemberAttribute; + } + } + + + private static Type typeOfEnumMemberAttribute; + internal static Type TypeOfEnumMemberAttribute + { + + get + { + if (typeOfEnumMemberAttribute == null) + { + typeOfEnumMemberAttribute = typeof(System.Runtime.Serialization.EnumMemberAttribute); + } + + return typeOfEnumMemberAttribute; + } + } + + + private static Type typeOfCollectionDataContractAttribute; + internal static Type TypeOfCollectionDataContractAttribute + { + + get + { + if (typeOfCollectionDataContractAttribute == null) + { + typeOfCollectionDataContractAttribute = typeof(System.Runtime.Serialization.CollectionDataContractAttribute); + } + + return typeOfCollectionDataContractAttribute; + } + } + + + private static Type typeOfOptionalFieldAttribute; + internal static Type TypeOfOptionalFieldAttribute + { + + get + { + if (typeOfOptionalFieldAttribute == null) + { + typeOfOptionalFieldAttribute = typeof(System.Runtime.Serialization.OptionalFieldAttribute); + } + + return typeOfOptionalFieldAttribute; + } + } + + + private static Type typeOfObjectArray; + internal static Type TypeOfObjectArray + { + + get + { + if (typeOfObjectArray == null) + { + typeOfObjectArray = typeof(object[]); + } + + return typeOfObjectArray; + } + } + + + private static Type typeOfOnSerializingAttribute; + internal static Type TypeOfOnSerializingAttribute + { + + get + { + if (typeOfOnSerializingAttribute == null) + { + typeOfOnSerializingAttribute = typeof(System.Runtime.Serialization.OnSerializingAttribute); + } + + return typeOfOnSerializingAttribute; + } + } + + + private static Type typeOfOnSerializedAttribute; + internal static Type TypeOfOnSerializedAttribute + { + + get + { + if (typeOfOnSerializedAttribute == null) + { + typeOfOnSerializedAttribute = typeof(System.Runtime.Serialization.OnSerializedAttribute); + } + + return typeOfOnSerializedAttribute; + } + } + + + private static Type typeOfOnDeserializingAttribute; + internal static Type TypeOfOnDeserializingAttribute + { + + get + { + if (typeOfOnDeserializingAttribute == null) + { + typeOfOnDeserializingAttribute = typeof(System.Runtime.Serialization.OnDeserializingAttribute); + } + + return typeOfOnDeserializingAttribute; + } + } + + + private static Type typeOfOnDeserializedAttribute; + internal static Type TypeOfOnDeserializedAttribute + { + + get + { + if (typeOfOnDeserializedAttribute == null) + { + typeOfOnDeserializedAttribute = typeof(System.Runtime.Serialization.OnDeserializedAttribute); + } + + return typeOfOnDeserializedAttribute; + } + } + + + private static Type typeOfFlagsAttribute; + internal static Type TypeOfFlagsAttribute + { + + get + { + if (typeOfFlagsAttribute == null) + { + typeOfFlagsAttribute = typeof(FlagsAttribute); + } + + return typeOfFlagsAttribute; + } + } + + + private static Type typeOfSerializableAttribute; + internal static Type TypeOfSerializableAttribute + { + + get + { + if (typeOfSerializableAttribute == null) + { + typeOfSerializableAttribute = typeof(SerializableAttribute); + } + + return typeOfSerializableAttribute; + } + } + + + private static Type typeOfNonSerializedAttribute; + internal static Type TypeOfNonSerializedAttribute + { + + get + { + if (typeOfNonSerializedAttribute == null) + { + typeOfNonSerializedAttribute = typeof(NonSerializedAttribute); + } + + return typeOfNonSerializedAttribute; + } + } + + + private static Type typeOfSerializationInfo; + internal static Type TypeOfSerializationInfo + { + + get + { + if (typeOfSerializationInfo == null) + { + typeOfSerializationInfo = typeof(System.Runtime.Serialization.SerializationInfo); + } + + return typeOfSerializationInfo; + } + } + + + private static Type typeOfSerializationInfoEnumerator; + internal static Type TypeOfSerializationInfoEnumerator + { + + get + { + if (typeOfSerializationInfoEnumerator == null) + { + typeOfSerializationInfoEnumerator = typeof(System.Runtime.Serialization.SerializationInfoEnumerator); + } + + return typeOfSerializationInfoEnumerator; + } + } + + + private static Type typeOfSerializationEntry; + internal static Type TypeOfSerializationEntry + { + + get + { + if (typeOfSerializationEntry == null) + { + typeOfSerializationEntry = typeof(System.Runtime.Serialization.SerializationEntry); + } + + return typeOfSerializationEntry; + } + } + + + private static Type typeOfIXmlSerializable; + internal static Type TypeOfIXmlSerializable + { + + get + { + if (typeOfIXmlSerializable == null) + { + typeOfIXmlSerializable = typeof(IXmlSerializable); + } + + return typeOfIXmlSerializable; + } + } + + + private static Type typeOfXmlSchemaProviderAttribute; + internal static Type TypeOfXmlSchemaProviderAttribute + { + + get + { + if (typeOfXmlSchemaProviderAttribute == null) + { + typeOfXmlSchemaProviderAttribute = typeof(XmlSchemaProviderAttribute); + } + + return typeOfXmlSchemaProviderAttribute; + } + } + + + private static Type typeOfXmlRootAttribute; + internal static Type TypeOfXmlRootAttribute + { + + get + { + if (typeOfXmlRootAttribute == null) + { + typeOfXmlRootAttribute = typeof(XmlRootAttribute); + } + + return typeOfXmlRootAttribute; + } + } + + + private static Type typeOfXmlQualifiedName; + internal static Type TypeOfXmlQualifiedName + { + + get + { + if (typeOfXmlQualifiedName == null) + { + typeOfXmlQualifiedName = typeof(XmlQualifiedName); + } + + return typeOfXmlQualifiedName; + } + } + + + private static Type typeOfXmlSchemaType; + internal static Type TypeOfXmlSchemaType + { + + get + { + if (typeOfXmlSchemaType == null) + { + typeOfXmlSchemaType = typeof(XmlSchemaType); + } + + return typeOfXmlSchemaType; + } + } + + + private static Type typeOfXmlSerializableServices; + internal static Type TypeOfXmlSerializableServices + { + + get + { + if (typeOfXmlSerializableServices == null) + { + typeOfXmlSerializableServices = typeof(System.Runtime.Serialization.XmlSerializableServices); + } + + return typeOfXmlSerializableServices; + } + } + + + private static Type typeOfXmlNodeArray; + internal static Type TypeOfXmlNodeArray + { + + get + { + if (typeOfXmlNodeArray == null) + { + typeOfXmlNodeArray = typeof(XmlNode[]); + } + + return typeOfXmlNodeArray; + } + } + + + private static Type typeOfXmlSchemaSet; + internal static Type TypeOfXmlSchemaSet + { + + get + { + if (typeOfXmlSchemaSet == null) + { + typeOfXmlSchemaSet = typeof(XmlSchemaSet); + } + + return typeOfXmlSchemaSet; + } + } + + + private static object[] emptyObjectArray; + internal static object[] EmptyObjectArray + { + + get + { + if (emptyObjectArray == null) + { + emptyObjectArray = new object[0]; + } + + return emptyObjectArray; + } + } + + + private static Type[] emptyTypeArray; + internal static Type[] EmptyTypeArray + { + + get + { + if (emptyTypeArray == null) + { + emptyTypeArray = new Type[0]; + } + + return emptyTypeArray; + } + } + + + private static Type typeOfIPropertyChange; + internal static Type TypeOfIPropertyChange + { + + get + { + if (typeOfIPropertyChange == null) + { + typeOfIPropertyChange = typeof(INotifyPropertyChanged); + } + + return typeOfIPropertyChange; + } + } + + + private static Type typeOfIExtensibleDataObject; + internal static Type TypeOfIExtensibleDataObject + { + + get + { + if (typeOfIExtensibleDataObject == null) + { + typeOfIExtensibleDataObject = typeof(System.Runtime.Serialization.IExtensibleDataObject); + } + + return typeOfIExtensibleDataObject; + } + } + + + private static Type typeOfExtensionDataObject; + internal static Type TypeOfExtensionDataObject + { + + get + { + if (typeOfExtensionDataObject == null) + { + typeOfExtensionDataObject = typeof(ExtensionDataObject); + } + + return typeOfExtensionDataObject; + } + } + + + private static Type typeOfISerializableDataNode; + internal static Type TypeOfISerializableDataNode + { + + get + { + if (typeOfISerializableDataNode == null) + { + typeOfISerializableDataNode = typeof(ISerializableDataNode); + } + + return typeOfISerializableDataNode; + } + } + + + private static Type typeOfClassDataNode; + internal static Type TypeOfClassDataNode + { + + get + { + if (typeOfClassDataNode == null) + { + typeOfClassDataNode = typeof(ClassDataNode); + } + + return typeOfClassDataNode; + } + } + + + private static Type typeOfCollectionDataNode; + internal static Type TypeOfCollectionDataNode + { + + get + { + if (typeOfCollectionDataNode == null) + { + typeOfCollectionDataNode = typeof(CollectionDataNode); + } + + return typeOfCollectionDataNode; + } + } + + + private static Type typeOfXmlDataNode; + internal static Type TypeOfXmlDataNode + { + + get + { + if (typeOfXmlDataNode == null) + { + typeOfXmlDataNode = typeof(XmlDataNode); + } + + return typeOfXmlDataNode; + } + } + + + private static Type typeOfNullable; + internal static Type TypeOfNullable + { + + get + { + if (typeOfNullable == null) + { + typeOfNullable = typeof(Nullable<>); + } + + return typeOfNullable; + } + } + + + private static Type typeOfReflectionPointer; + internal static Type TypeOfReflectionPointer + { + + get + { + if (typeOfReflectionPointer == null) + { + typeOfReflectionPointer = typeof(System.Reflection.Pointer); + } + + return typeOfReflectionPointer; + } + } + + + private static Type typeOfIDictionaryGeneric; + internal static Type TypeOfIDictionaryGeneric + { + + get + { + if (typeOfIDictionaryGeneric == null) + { + typeOfIDictionaryGeneric = typeof(IDictionary<,>); + } + + return typeOfIDictionaryGeneric; + } + } + + + private static Type typeOfIDictionary; + internal static Type TypeOfIDictionary + { + + get + { + if (typeOfIDictionary == null) + { + typeOfIDictionary = typeof(IDictionary); + } + + return typeOfIDictionary; + } + } + + + private static Type typeOfIListGeneric; + internal static Type TypeOfIListGeneric + { + + get + { + if (typeOfIListGeneric == null) + { + typeOfIListGeneric = typeof(IList<>); + } + + return typeOfIListGeneric; + } + } + + + private static Type typeOfIList; + internal static Type TypeOfIList + { + + get + { + if (typeOfIList == null) + { + typeOfIList = typeof(IList); + } + + return typeOfIList; + } + } + + + private static Type typeOfICollectionGeneric; + internal static Type TypeOfICollectionGeneric + { + + get + { + if (typeOfICollectionGeneric == null) + { + typeOfICollectionGeneric = typeof(ICollection<>); + } + + return typeOfICollectionGeneric; + } + } + + + private static Type typeOfICollection; + internal static Type TypeOfICollection + { + + get + { + if (typeOfICollection == null) + { + typeOfICollection = typeof(ICollection); + } + + return typeOfICollection; + } + } + + + private static Type typeOfIEnumerableGeneric; + internal static Type TypeOfIEnumerableGeneric + { + + get + { + if (typeOfIEnumerableGeneric == null) + { + typeOfIEnumerableGeneric = typeof(IEnumerable<>); + } + + return typeOfIEnumerableGeneric; + } + } + + + private static Type typeOfIEnumerable; + internal static Type TypeOfIEnumerable + { + + get + { + if (typeOfIEnumerable == null) + { + typeOfIEnumerable = typeof(IEnumerable); + } + + return typeOfIEnumerable; + } + } + + + private static Type typeOfIEnumeratorGeneric; + internal static Type TypeOfIEnumeratorGeneric + { + + get + { + if (typeOfIEnumeratorGeneric == null) + { + typeOfIEnumeratorGeneric = typeof(IEnumerator<>); + } + + return typeOfIEnumeratorGeneric; + } + } + + + private static Type typeOfIEnumerator; + internal static Type TypeOfIEnumerator + { + + get + { + if (typeOfIEnumerator == null) + { + typeOfIEnumerator = typeof(IEnumerator); + } + + return typeOfIEnumerator; + } + } + + + private static Type typeOfKeyValuePair; + internal static Type TypeOfKeyValuePair + { + + get + { + if (typeOfKeyValuePair == null) + { + typeOfKeyValuePair = typeof(KeyValuePair<,>); + } + + return typeOfKeyValuePair; + } + } + + + private static Type typeOfKeyValue; + internal static Type TypeOfKeyValue + { + + get + { + if (typeOfKeyValue == null) + { + typeOfKeyValue = typeof(KeyValue<,>); + } + + return typeOfKeyValue; + } + } + + + private static Type typeOfIDictionaryEnumerator; + internal static Type TypeOfIDictionaryEnumerator + { + + get + { + if (typeOfIDictionaryEnumerator == null) + { + typeOfIDictionaryEnumerator = typeof(IDictionaryEnumerator); + } + + return typeOfIDictionaryEnumerator; + } + } + + + private static Type typeOfDictionaryEnumerator; + internal static Type TypeOfDictionaryEnumerator + { + + get + { + if (typeOfDictionaryEnumerator == null) + { + typeOfDictionaryEnumerator = typeof(CollectionDataContract.DictionaryEnumerator); + } + + return typeOfDictionaryEnumerator; + } + } + + + private static Type typeOfGenericDictionaryEnumerator; + internal static Type TypeOfGenericDictionaryEnumerator + { + + get + { + if (typeOfGenericDictionaryEnumerator == null) + { + typeOfGenericDictionaryEnumerator = typeof(CollectionDataContract.GenericDictionaryEnumerator<,>); + } + + return typeOfGenericDictionaryEnumerator; + } + } + + + private static Type typeOfDictionaryGeneric; + internal static Type TypeOfDictionaryGeneric + { + + get + { + if (typeOfDictionaryGeneric == null) + { + typeOfDictionaryGeneric = typeof(Dictionary<,>); + } + + return typeOfDictionaryGeneric; + } + } + + + private static Type typeOfHashtable; + internal static Type TypeOfHashtable + { + + get + { + if (typeOfHashtable == null) + { + typeOfHashtable = typeof(Hashtable); + } + + return typeOfHashtable; + } + } + + + private static Type typeOfListGeneric; + internal static Type TypeOfListGeneric + { + + get + { + if (typeOfListGeneric == null) + { + typeOfListGeneric = typeof(List<>); + } + + return typeOfListGeneric; + } + } + + + private static Type typeOfXmlElement; + internal static Type TypeOfXmlElement + { + + get + { + if (typeOfXmlElement == null) + { + typeOfXmlElement = typeof(XmlElement); + } + + return typeOfXmlElement; + } + } + + + private static Type typeOfDBNull; + internal static Type TypeOfDBNull + { + + get + { + if (typeOfDBNull == null) + { + typeOfDBNull = typeof(DBNull); + } + + return typeOfDBNull; + } + } + + + private static Uri dataContractXsdBaseNamespaceUri; + internal static Uri DataContractXsdBaseNamespaceUri + { + + get + { + if (dataContractXsdBaseNamespaceUri == null) + { + dataContractXsdBaseNamespaceUri = new Uri(DataContractXsdBaseNamespace); + } + + return dataContractXsdBaseNamespaceUri; + } + } + + + public const bool DefaultIsRequired = false; + public const bool DefaultEmitDefaultValue = true; + public const int DefaultOrder = 0; + public const bool DefaultIsReference = false; + // The value string.Empty aids comparisons (can do simple length checks + // instead of string comparison method calls in IL.) + public static readonly string NewObjectId = string.Empty; + public const string SimpleSRSInternalsVisiblePattern = @"^[\s]*System\.Runtime\.Serialization[\s]*$"; + public const string FullSRSInternalsVisiblePattern = @"^[\s]*System\.Runtime\.Serialization[\s]*,[\s]*PublicKey[\s]*=[\s]*(?i:00000000000000000400000000000000)[\s]*$"; + public const string NullObjectId = null; + public const string Space = " "; + public const string OpenBracket = "["; + public const string CloseBracket = "]"; + public const string Comma = ","; + public const string XsiPrefix = "i"; + public const string XsdPrefix = "x"; + public const string SerPrefix = "z"; + public const string SerPrefixForSchema = "ser"; + public const string ElementPrefix = "q"; + public const string DataContractXsdBaseNamespace = "http://schemas.datacontract.org/2004/07/"; + public const string DataContractXmlNamespace = DataContractXsdBaseNamespace + "System.Xml"; + public const string SchemaInstanceNamespace = XmlSchema.InstanceNamespace; + public const string SchemaNamespace = XmlSchema.Namespace; + public const string XsiNilLocalName = "nil"; + public const string XsiTypeLocalName = "type"; + public const string TnsPrefix = "tns"; + public const string OccursUnbounded = "unbounded"; + public const string AnyTypeLocalName = "anyType"; + public const string StringLocalName = "string"; + public const string IntLocalName = "int"; + public const string True = "true"; + public const string False = "false"; + public const string ArrayPrefix = "ArrayOf"; + public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; + public const string XmlnsPrefix = "xmlns"; + public const string SchemaLocalName = "schema"; + public const string CollectionsNamespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; + public const string DefaultClrNamespace = "GeneratedNamespace"; + public const string DefaultTypeName = "GeneratedType"; + public const string DefaultGeneratedMember = "GeneratedMember"; + public const string DefaultFieldSuffix = "Field"; + public const string DefaultPropertySuffix = "Property"; + public const string DefaultMemberSuffix = "Member"; + public const string NameProperty = "Name"; + public const string NamespaceProperty = "Namespace"; + public const string OrderProperty = "Order"; + public const string IsReferenceProperty = "IsReference"; + public const string IsRequiredProperty = "IsRequired"; + public const string EmitDefaultValueProperty = "EmitDefaultValue"; + public const string ClrNamespaceProperty = "ClrNamespace"; + public const string ItemNameProperty = "ItemName"; + public const string KeyNameProperty = "KeyName"; + public const string ValueNameProperty = "ValueName"; + public const string SerializationInfoPropertyName = "SerializationInfo"; + public const string SerializationInfoFieldName = "info"; + public const string NodeArrayPropertyName = "Nodes"; + public const string NodeArrayFieldName = "nodesField"; + public const string ExportSchemaMethod = "ExportSchema"; + public const string IsAnyProperty = "IsAny"; + public const string ContextFieldName = "context"; + public const string GetObjectDataMethodName = "GetObjectData"; + public const string GetEnumeratorMethodName = "GetEnumerator"; + public const string MoveNextMethodName = "MoveNext"; + public const string AddValueMethodName = "AddValue"; + public const string CurrentPropertyName = "Current"; + public const string ValueProperty = "Value"; + public const string EnumeratorFieldName = "enumerator"; + public const string SerializationEntryFieldName = "entry"; + public const string ExtensionDataSetMethod = "set_ExtensionData"; + public const string ExtensionDataSetExplicitMethod = "System.Runtime.Serialization.IExtensibleDataObject.set_ExtensionData"; + public const string ExtensionDataObjectPropertyName = "ExtensionData"; + public const string ExtensionDataObjectFieldName = "extensionDataField"; + public const string AddMethodName = "Add"; + public const string ParseMethodName = "Parse"; + public const string GetCurrentMethodName = "get_Current"; + // NOTE: These values are used in schema below. If you modify any value, please make the same change in the schema. + public const string SerializationNamespace = "http://schemas.microsoft.com/2003/10/Serialization/"; + public const string ClrTypeLocalName = "Type"; + public const string ClrAssemblyLocalName = "Assembly"; + public const string IsValueTypeLocalName = "IsValueType"; + public const string EnumerationValueLocalName = "EnumerationValue"; + public const string SurrogateDataLocalName = "Surrogate"; + public const string GenericTypeLocalName = "GenericType"; + public const string GenericParameterLocalName = "GenericParameter"; + public const string GenericNameAttribute = "Name"; + public const string GenericNamespaceAttribute = "Namespace"; + public const string GenericParameterNestedLevelAttribute = "NestedLevel"; + public const string IsDictionaryLocalName = "IsDictionary"; + public const string ActualTypeLocalName = "ActualType"; + public const string ActualTypeNameAttribute = "Name"; + public const string ActualTypeNamespaceAttribute = "Namespace"; + public const string DefaultValueLocalName = "DefaultValue"; + public const string EmitDefaultValueAttribute = "EmitDefaultValue"; + public const string ISerializableFactoryTypeLocalName = "FactoryType"; + public const string IdLocalName = "Id"; + public const string RefLocalName = "Ref"; + public const string ArraySizeLocalName = "Size"; + public const string KeyLocalName = "Key"; + public const string ValueLocalName = "Value"; + public const string MscorlibAssemblyName = "0"; + public const string MscorlibAssemblySimpleName = "mscorlib"; + public const string MscorlibFileName = MscorlibAssemblySimpleName + ".dll"; + public const string SerializationSchema = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/HybridObjectCache.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/HybridObjectCache.cs new file mode 100644 index 0000000..18b6245 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/HybridObjectCache.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + internal class HybridObjectCache + { + private Dictionary _objectDictionary; + private Dictionary _referencedObjectDictionary; + + internal HybridObjectCache() + { + } + + internal void Add(string id, object obj) + { + if (_objectDictionary == null) + { + _objectDictionary = new Dictionary(); + } + + if (_objectDictionary.TryGetValue(id, out object existingObject)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.MultipleIdDefinition, id))); + } + + _objectDictionary.Add(id, obj); + } + + internal void Remove(string id) + { + if (_objectDictionary != null) + { + _objectDictionary.Remove(id); + } + } + + internal object GetObject(string id) + { + if (_referencedObjectDictionary == null) + { + _referencedObjectDictionary = new Dictionary + { + { id, null } + }; + } + else if (!_referencedObjectDictionary.ContainsKey(id)) + { + _referencedObjectDictionary.Add(id, null); + } + + if (_objectDictionary != null) + { + _objectDictionary.TryGetValue(id, out object obj); + return obj; + } + + return null; + } + + internal bool IsObjectReferenced(string id) + { + if (_referencedObjectDictionary != null) + { + return _referencedObjectDictionary.ContainsKey(id); + } + return false; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/IDataContractSurrogate.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/IDataContractSurrogate.cs new file mode 100644 index 0000000..fced9be --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/IDataContractSurrogate.cs @@ -0,0 +1,17 @@ +using System; +using System.Reflection; +using System.Collections.ObjectModel; + +namespace Compat.Runtime.Serialization +{ + public interface IDataContractSurrogate + { + Type GetDataContractType(Type type); + object GetObjectToSerialize(object obj, Type targetType); + object GetDeserializedObject(object obj, Type targetType); + object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); + object GetCustomDataToExport(Type clrType, Type dataContractType); + void GetKnownCustomDataTypes(Collection customDataTypes); + Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData); + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/IDataNode.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/IDataNode.cs new file mode 100644 index 0000000..34c8474 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/IDataNode.cs @@ -0,0 +1,21 @@ +using System; + +namespace Compat.Runtime.Serialization +{ + internal interface IDataNode + { + Type DataType { get; } + object Value { get; set; } // boxes for primitives + string DataContractName { get; set; } + string DataContractNamespace { get; set; } + string ClrTypeName { get; set; } + string ClrAssemblyName { get; set; } + string Id { get; set; } + bool PreservesReferences { get; } + + // NOTE: consider moving below APIs to DataNode if IDataNode API is made public + void GetData(ElementData element); + bool IsFinalValue { get; set; } + void Clear(); + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataMember.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataMember.cs new file mode 100644 index 0000000..703bc4f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataMember.cs @@ -0,0 +1,9 @@ +namespace Compat.Runtime.Serialization +{ + internal class ISerializableDataMember + { + internal string Name { get; set; } + + internal IDataNode Value { get; set; } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataNode.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataNode.cs new file mode 100644 index 0000000..e54dba3 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ISerializableDataNode.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + internal class ISerializableDataNode : DataNode + { + private string _factoryTypeName; + private string _factoryTypeNamespace; + private IList _members; + + internal ISerializableDataNode() + { + dataType = Globals.TypeOfISerializableDataNode; + } + + internal string FactoryTypeName + { + get => _factoryTypeName; + set => _factoryTypeName = value; + } + + internal string FactoryTypeNamespace + { + get => _factoryTypeNamespace; + set => _factoryTypeNamespace = value; + } + + internal IList Members + { + get => _members; + set => _members = value; + } + + public override void GetData(ElementData element) + { + base.GetData(element); + + if (FactoryTypeName != null) + { + AddQualifiedNameAttribute(element, Globals.SerPrefix, Globals.ISerializableFactoryTypeLocalName, Globals.SerializationNamespace, FactoryTypeName, FactoryTypeNamespace); + } + } + + public override void Clear() + { + base.Clear(); + _members = null; + _factoryTypeName = _factoryTypeNamespace = null; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/IntRef.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/IntRef.cs new file mode 100644 index 0000000..75f38b7 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/IntRef.cs @@ -0,0 +1,15 @@ +namespace Compat.Runtime.Serialization +{ + internal class IntRef + { + private readonly int _value; + + public IntRef(int value) + { + _value = value; + } + + public int Value => _value; + } + +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/KnownTypeDataContractResolver.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/KnownTypeDataContractResolver.cs new file mode 100644 index 0000000..317324f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/KnownTypeDataContractResolver.cs @@ -0,0 +1,58 @@ +using System; +using System.Xml; +using DataContractResolver = System.Runtime.Serialization.DataContractResolver; + +namespace Compat.Runtime.Serialization +{ + internal sealed class KnownTypeDataContractResolver : DataContractResolver + { + private readonly XmlObjectSerializerContext _context; + + internal KnownTypeDataContractResolver(XmlObjectSerializerContext context) + { + Fx.Assert(context != null, "KnownTypeDataContractResolver should not be instantiated with a null context"); + _context = context; + } + + public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) + { + if (type == null) + { + typeName = null; + typeNamespace = null; + return false; + } + + if (declaredType != null && declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType)) + { + typeName = null; + typeNamespace = null; + return true; + } + + DataContract contract = DataContract.GetDataContract(type); + if (_context.IsKnownType(contract, contract.KnownDataContracts, declaredType)) + { + typeName = contract.Name; + typeNamespace = contract.Namespace; + return true; + } + else + { + typeName = null; + typeNamespace = null; + return false; + } + } + + public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) + { + if (typeName == null || typeNamespace == null) + { + return null; + } + + return _context.ResolveNameFromKnownTypes(new XmlQualifiedName(typeName, typeNamespace)); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/NetDataContractSerializer.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/NetDataContractSerializer.cs new file mode 100644 index 0000000..1b8598c --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/NetDataContractSerializer.cs @@ -0,0 +1,599 @@ +using System; +using System.Collections; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization.Formatters; +using System.Xml; +using IFormatter = System.Runtime.Serialization.IFormatter; +using ISerializationSurrogate = System.Runtime.Serialization.ISerializationSurrogate; +using ISurrogateSelector = System.Runtime.Serialization.ISurrogateSelector; +using SerializationBinder = System.Runtime.Serialization.SerializationBinder; +using SerializationInfo = System.Runtime.Serialization.SerializationInfo; +using StreamingContext = System.Runtime.Serialization.StreamingContext; +using StreamingContextStates = System.Runtime.Serialization.StreamingContextStates; + +namespace Compat.Runtime.Serialization +{ + public sealed class NetDataContractSerializer : XmlObjectSerializer, IFormatter + { + private XmlDictionaryString rootName; + private XmlDictionaryString rootNamespace; + private StreamingContext context; + private SerializationBinder binder; + private ISurrogateSelector surrogateSelector; + private int maxItemsInObjectGraph; + private bool ignoreExtensionDataObject; + private FormatterAssemblyStyle assemblyFormat; + private DataContract cachedDataContract; + private static readonly Hashtable typeNameCache = new Hashtable(); + + public NetDataContractSerializer() + : this(new StreamingContext(StreamingContextStates.All)) + { + } + + public NetDataContractSerializer(StreamingContext context) + : this(context, int.MaxValue, false, FormatterAssemblyStyle.Full, null) + { + } + + public NetDataContractSerializer(StreamingContext context, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + FormatterAssemblyStyle assemblyFormat, + ISurrogateSelector surrogateSelector) + { + Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector); + } + + public NetDataContractSerializer(string rootName, string rootNamespace) + : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), int.MaxValue, false, FormatterAssemblyStyle.Full, null) + { + } + + public NetDataContractSerializer(string rootName, string rootNamespace, + StreamingContext context, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + FormatterAssemblyStyle assemblyFormat, + ISurrogateSelector surrogateSelector) + { + XmlDictionary dictionary = new XmlDictionary(2); + Initialize(dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector); + } + + public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace) + : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), int.MaxValue, false, FormatterAssemblyStyle.Full, null) + { + } + + public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace, + StreamingContext context, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + FormatterAssemblyStyle assemblyFormat, + ISurrogateSelector surrogateSelector) + { + Initialize(rootName, rootNamespace, context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector); + } + + private void Initialize(StreamingContext context, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + FormatterAssemblyStyle assemblyFormat, + ISurrogateSelector surrogateSelector) + { + this.context = context; + if (maxItemsInObjectGraph < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(maxItemsInObjectGraph), SR.ValueMustBeNonNegative)); + } + + this.maxItemsInObjectGraph = maxItemsInObjectGraph; + this.ignoreExtensionDataObject = ignoreExtensionDataObject; + this.surrogateSelector = surrogateSelector; + AssemblyFormat = assemblyFormat; + } + + private void Initialize(XmlDictionaryString rootName, XmlDictionaryString rootNamespace, + StreamingContext context, + int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, + FormatterAssemblyStyle assemblyFormat, + ISurrogateSelector surrogateSelector) + { + Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector); + this.rootName = rootName; + this.rootNamespace = rootNamespace; + } + + public StreamingContext Context + { + get => context; + set => context = value; + } + + public SerializationBinder Binder + { + get => binder; + set => binder = value; + } + + public ISurrogateSelector SurrogateSelector + { + get => surrogateSelector; + set => surrogateSelector = value; + } + + public FormatterAssemblyStyle AssemblyFormat + { + get => assemblyFormat; + set + { + if (value != FormatterAssemblyStyle.Full && value != FormatterAssemblyStyle.Simple) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.InvalidAssemblyFormat, value))); + } + + assemblyFormat = value; + } + } + + public int MaxItemsInObjectGraph => maxItemsInObjectGraph; + + public bool IgnoreExtensionDataObject => ignoreExtensionDataObject; + + public void Serialize(Stream stream, object graph) + { + base.WriteObject(stream, graph); + } + + public object Deserialize(Stream stream) + { + return base.ReadObject(stream); + } + + public object Deserialize(XmlReader reader) + { + return base.ReadObject(reader); + } + + internal override void InternalWriteObject(XmlWriterDelegator writer, object graph) + { + Hashtable surrogateDataContracts = null; + DataContract contract = GetDataContract(graph, ref surrogateDataContracts); + + InternalWriteStartObject(writer, graph, contract); + InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts); + InternalWriteEndObject(writer); + } + + public override void WriteObject(XmlWriter writer, object graph) + { + WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteStartObject(XmlWriter writer, object graph) + { + WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteObjectContent(XmlWriter writer, object graph) + { + WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + public override void WriteEndObject(XmlWriter writer) + { + WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer)); + } + + public override void WriteStartObject(XmlDictionaryWriter writer, object graph) + { + WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + internal override void InternalWriteStartObject(XmlWriterDelegator writer, object graph) + { + Hashtable surrogateDataContracts = null; + DataContract contract = GetDataContract(graph, ref surrogateDataContracts); + InternalWriteStartObject(writer, graph, contract); + } + + private void InternalWriteStartObject(XmlWriterDelegator writer, object graph, DataContract contract) + { + WriteRootElement(writer, contract, rootName, rootNamespace, CheckIfNeedsContractNsAtRoot(rootName, rootNamespace, contract)); + } + + public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) + { + WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + internal override void InternalWriteObjectContent(XmlWriterDelegator writer, object graph) + { + Hashtable surrogateDataContracts = null; + DataContract contract = GetDataContract(graph, ref surrogateDataContracts); + InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts); + } + + private void InternalWriteObjectContent(XmlWriterDelegator writer, object graph, DataContract contract, Hashtable surrogateDataContracts) + { + if (MaxItemsInObjectGraph == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph))); + } + + if (IsRootXmlAny(rootName, contract)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsAnyNotSupportedByNetDataContractSerializer, contract.UnderlyingType))); + } + else if (graph == null) + { + WriteNull(writer); + } + else + { + Type graphType = graph.GetType(); + if (contract.UnderlyingType != graphType) + { + contract = GetDataContract(graph, ref surrogateDataContracts); + } + + XmlObjectSerializerWriteContext context = null; + if (contract.CanContainReferences) + { + context = XmlObjectSerializerWriteContext.CreateContext(this, surrogateDataContracts); + context.HandleGraphAtTopLevel(writer, graph, contract); + } + + WriteClrTypeInfo(writer, contract, binder); + contract.WriteXmlValue(writer, graph, context); + } + } + + // Update the overloads whenever you are changing this method + internal static void WriteClrTypeInfo(XmlWriterDelegator writer, DataContract dataContract, SerializationBinder binder) + { + if (!dataContract.IsISerializable && !(dataContract is SurrogateDataContract)) + { + TypeInformation typeInformation = null; + Type clrType = dataContract.OriginalUnderlyingType; + string clrTypeName = null; + string clrAssemblyName = null; + + if (binder != null) + { + binder.BindToName(clrType, out clrAssemblyName, out clrTypeName); + } + + if (clrTypeName == null) + { + typeInformation = NetDataContractSerializer.GetTypeInformation(clrType); + clrTypeName = typeInformation.FullTypeName; + } + + if (clrAssemblyName == null) + { + clrAssemblyName = (typeInformation == null) ? + NetDataContractSerializer.GetTypeInformation(clrType).AssemblyString : + typeInformation.AssemblyString; + + // Throw in the [TypeForwardedFrom] case to prevent a partially trusted assembly from forwarding itself to an assembly with higher privileges + if (!UnsafeTypeForwardingEnabled && !clrType.Assembly.IsFullyTrusted && !IsAssemblyNameForwardingSafe(clrType.Assembly.FullName, clrAssemblyName)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.TypeCannotBeForwardedFrom, DataContract.GetClrTypeFullName(clrType), clrType.Assembly.FullName, clrAssemblyName))); + } + } + + WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName); + } + } + + public static bool UnsafeTypeForwardingEnabled => false; + + // Update the overloads whenever you are changing this method + internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, string defaultClrTypeName, string defaultClrAssemblyName) + { + string clrTypeName = null; + string clrAssemblyName = null; + + if (binder != null) + { + binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName); + } + + if (clrTypeName == null) + { + clrTypeName = defaultClrTypeName; + } + + if (clrAssemblyName == null) + { + clrAssemblyName = defaultClrAssemblyName; + } + + WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName); + } + + // Update the overloads whenever you are changing this method + internal static void WriteClrTypeInfo( + XmlWriterDelegator writer, + Type dataContractType, + SerializationBinder binder, + SerializationInfo serInfo) + { + TypeInformation typeInformation = null; + string clrTypeName = null; + string clrAssemblyName = null; + + if (binder != null) + { + binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName); + } + + if (clrTypeName == null) + { + if (serInfo.IsFullTypeNameSetExplicit) + { + clrTypeName = serInfo.FullTypeName; + } + else + { + typeInformation = NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType); + clrTypeName = typeInformation.FullTypeName; + } + } + + if (clrAssemblyName == null) + { + if (serInfo.IsAssemblyNameSetExplicit) + { + clrAssemblyName = serInfo.AssemblyName; + } + else + { + clrAssemblyName = (typeInformation == null) ? + NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType).AssemblyString : + typeInformation.AssemblyString; + } + } + + WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName); + } + + private static void WriteClrTypeInfo(XmlWriterDelegator writer, string clrTypeName, string clrAssemblyName) + { + if (clrTypeName != null) + { + writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrTypeName)); + } + + if (clrAssemblyName != null) + { + writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrAssemblyLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrAssemblyName)); + } + } + + public override void WriteEndObject(XmlDictionaryWriter writer) + { + WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer)); + } + + internal override void InternalWriteEndObject(XmlWriterDelegator writer) + { + writer.WriteEndElement(); + } + + public override object ReadObject(XmlReader reader) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/); + } + + public override object ReadObject(XmlReader reader, bool verifyObjectName) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName); + } + + public override bool IsStartObject(XmlReader reader) + { + return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader)); + } + + public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName); + } + + public override bool IsStartObject(XmlDictionaryReader reader) + { + return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader)); + } + + internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName) + { + if (MaxItemsInObjectGraph == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph))); + } + + // verifyObjectName has no effect in SharedType mode + if (!IsStartElement(xmlReader)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.Format(SR.ExpectingElementAtDeserialize, XmlNodeType.Element), xmlReader)); + } + + XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext.CreateContext(this); + return context.InternalDeserialize(xmlReader, null, null, null); + } + + internal override bool InternalIsStartObject(XmlReaderDelegator reader) + { + return IsStartElement(reader); + } + + internal DataContract GetDataContract(object obj, ref Hashtable surrogateDataContracts) + { + return GetDataContract(((obj == null) ? Globals.TypeOfObject : obj.GetType()), ref surrogateDataContracts); + } + + internal DataContract GetDataContract(Type type, ref Hashtable surrogateDataContracts) + { + return GetDataContract(type.TypeHandle, type, ref surrogateDataContracts); + } + + internal DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts) + { + DataContract dataContract = GetDataContractFromSurrogateSelector(surrogateSelector, Context, typeHandle, type, ref surrogateDataContracts); + if (dataContract != null) + { + return dataContract; + } + + if (cachedDataContract == null) + { + dataContract = DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType); + cachedDataContract = dataContract; + return dataContract; + } + + DataContract currentCachedDataContract = cachedDataContract; + if (currentCachedDataContract.UnderlyingType.TypeHandle.Equals(typeHandle)) + { + return currentCachedDataContract; + } + + return DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static ISerializationSurrogate GetSurrogate( + Type type, + ISurrogateSelector surrogateSelector, + StreamingContext context) + { + return surrogateSelector.GetSurrogate(type, context, out ISurrogateSelector surrogateSelectorNotUsed); + } + + internal static DataContract GetDataContractFromSurrogateSelector( + ISurrogateSelector surrogateSelector, + StreamingContext context, + RuntimeTypeHandle typeHandle, + Type type, + ref Hashtable surrogateDataContracts) + { + if (surrogateSelector == null) + { + return null; + } + + if (type == null) + { + type = Type.GetTypeFromHandle(typeHandle); + } + + DataContract builtInDataContract = DataContract.GetBuiltInDataContract(type); + if (builtInDataContract != null) + { + return builtInDataContract; + } + + if (surrogateDataContracts != null) + { + DataContract cachedSurrogateContract = (DataContract)surrogateDataContracts[type]; + if (cachedSurrogateContract != null) + { + return cachedSurrogateContract; + } + } + DataContract surrogateContract = null; + ISerializationSurrogate surrogate = GetSurrogate(type, surrogateSelector, context); + if (surrogate != null) + { + surrogateContract = new SurrogateDataContract(type, surrogate); + } + else if (type.IsArray) + { + Type elementType = type.GetElementType(); + DataContract itemContract = GetDataContractFromSurrogateSelector(surrogateSelector, context, elementType.TypeHandle, elementType, ref surrogateDataContracts); + if (itemContract == null) + { + itemContract = DataContract.GetDataContract(elementType.TypeHandle, elementType, SerializationMode.SharedType); + } + + surrogateContract = new CollectionDataContract(type, itemContract); + } + if (surrogateContract != null) + { + if (surrogateDataContracts == null) + { + surrogateDataContracts = new Hashtable(); + } + + surrogateDataContracts.Add(type, surrogateContract); + return surrogateContract; + } + return null; + } + + + internal static TypeInformation GetTypeInformation(Type type) + { + TypeInformation typeInformation = null; + object typeInformationObject = typeNameCache[type]; + if (typeInformationObject == null) + { + string assemblyName = DataContract.GetClrAssemblyName(type, out bool hasTypeForwardedFrom); + typeInformation = new TypeInformation(DataContract.GetClrTypeFullNameUsingTypeForwardedFromAttribute(type), assemblyName, hasTypeForwardedFrom); + lock (typeNameCache) + { + typeNameCache[type] = typeInformation; + } + } + else + { + typeInformation = (TypeInformation)typeInformationObject; + } + return typeInformation; + } + + private static bool IsAssemblyNameForwardingSafe(string originalAssemblyName, string newAssemblyName) + { + if (originalAssemblyName == newAssemblyName) + { + return true; + } + + AssemblyName originalAssembly = new AssemblyName(originalAssemblyName); + AssemblyName newAssembly = new AssemblyName(newAssemblyName); + + // mscorlib will get loaded by the runtime regardless of its string casing or its public key token, + // so setting the assembly name to mscorlib is always unsafe + if (string.Equals(newAssembly.Name, Globals.MscorlibAssemblySimpleName, StringComparison.OrdinalIgnoreCase) || + string.Equals(newAssembly.Name, Globals.MscorlibFileName, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return IsPublicKeyTokenForwardingSafe(originalAssembly.GetPublicKeyToken(), newAssembly.GetPublicKeyToken()); + } + + private static bool IsPublicKeyTokenForwardingSafe(byte[] sourceToken, byte[] destinationToken) + { + if (sourceToken == null || destinationToken == null || sourceToken.Length == 0 || destinationToken.Length == 0 || sourceToken.Length != destinationToken.Length) + { + return false; + } + + for (int i = 0; i < sourceToken.Length; i++) + { + if (sourceToken[i] != destinationToken[i]) + { + return false; + } + } + return true; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectReferenceStack.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectReferenceStack.cs new file mode 100644 index 0000000..1ce89fc --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectReferenceStack.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + internal struct ObjectReferenceStack + { + private const int MaximumArraySize = 16; + private const int InitialArraySize = 4; + private int count; + private object[] objectArray; + private bool[] isReferenceArray; + private Dictionary objectDictionary; + + internal void Push(object obj) + { + if (objectArray == null) + { + objectArray = new object[InitialArraySize]; + objectArray[count++] = obj; + } + else if (count < MaximumArraySize) + { + if (count == objectArray.Length) + { + Array.Resize(ref objectArray, objectArray.Length * 2); + } + + objectArray[count++] = obj; + } + else + { + if (objectDictionary == null) + { + objectDictionary = new Dictionary(); + } + + objectDictionary.Add(obj, null); + count++; + } + } + + internal void EnsureSetAsIsReference(object obj) + { + if (count == 0) + { + return; + } + + if (count > MaximumArraySize) + { + if (objectDictionary == null) + { + Fx.Assert("Object reference stack in invalid state"); + } + objectDictionary.Remove(obj); + } + else + { + if ((objectArray != null) && objectArray[count - 1] == obj) + { + if (isReferenceArray == null) + { + isReferenceArray = new bool[objectArray.Length]; + } + else if (count >= isReferenceArray.Length) + { + + Array.Resize(ref isReferenceArray, objectArray.Length); + } + isReferenceArray[count - 1] = true; + } + } + } + + internal void Pop(object obj) + { + if (count > MaximumArraySize) + { + if (objectDictionary == null) + { + Fx.Assert("Object reference stack in invalid state"); + } + objectDictionary.Remove(obj); + } + count--; + } + + internal bool Contains(object obj) + { + int currentCount = count; + if (currentCount > MaximumArraySize) + { + if (objectDictionary != null && objectDictionary.ContainsKey(obj)) + { + return true; + } + + currentCount = MaximumArraySize; + } + for (int i = (currentCount - 1); i >= 0; i--) + { + if (Object.ReferenceEquals(obj, objectArray[i]) && isReferenceArray != null && !isReferenceArray[i]) + { + return true; + } + } + return false; + } + + internal int Count => count; + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectToIdCache.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectToIdCache.cs new file mode 100644 index 0000000..e464a31 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ObjectToIdCache.cs @@ -0,0 +1,219 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Compat.Runtime.Serialization +{ + internal class ObjectToIdCache + { + internal int m_currentCount; + internal int[] m_ids; + internal object[] m_objs; + private bool[] m_isWrapped; + + public ObjectToIdCache() + { + m_currentCount = 1; + m_ids = new int[GetPrime(1)]; + m_objs = new object[m_ids.Length]; + m_isWrapped = new bool[m_ids.Length]; + } + + public int GetId(object obj, ref bool newId) + { + int position = FindElement(obj, out bool isEmpty, out bool isWrapped); + if (!isEmpty) + { + newId = false; + return m_ids[position]; + } + if (!newId) + { + return -1; + } + + int id = m_currentCount++; + m_objs[position] = obj; + m_ids[position] = id; + m_isWrapped[position] = isWrapped; + if (m_currentCount >= (m_objs.Length - 1)) + { + Rehash(); + } + + return id; + } + + // (oldObjId, oldObj-id, newObj-newObjId) => (oldObj-oldObjId, newObj-id, newObjId ) + public int ReassignId(int oldObjId, object oldObj, object newObj) + { + int position = FindElement(oldObj, out bool isEmpty, out bool isWrapped); + if (isEmpty) + { + return 0; + } + + int id = m_ids[position]; + if (oldObjId > 0) + { + m_ids[position] = oldObjId; + } + else + { + RemoveAt(position); + } + + position = FindElement(newObj, out isEmpty, out isWrapped); + int newObjId = 0; + if (!isEmpty) + { + newObjId = m_ids[position]; + } + + m_objs[position] = newObj; + m_ids[position] = id; + m_isWrapped[position] = isWrapped; + return newObjId; + } + + private int FindElement(object obj, out bool isEmpty, out bool isWrapped) + { + isWrapped = false; + int position = ComputeStartPosition(obj); + for (int i = position; i != (position - 1); i++) + { + if (m_objs[i] == null) + { + isEmpty = true; + return i; + } + if (m_objs[i] == obj) + { + isEmpty = false; + return i; + } + if (i == (m_objs.Length - 1)) + { + isWrapped = true; + i = -1; + } + } + // m_obj must ALWAYS have atleast one slot empty (null). + Fx.Assert("Object table overflow"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.ObjectTableOverflow)); + } + + private void RemoveAt(int position) + { + int cacheSize = m_objs.Length; + int lastVacantPosition = position; + for (int next = (position == cacheSize - 1) ? 0 : position + 1; next != position; next++) + { + if (m_objs[next] == null) + { + m_objs[lastVacantPosition] = null; + m_ids[lastVacantPosition] = 0; + m_isWrapped[lastVacantPosition] = false; + return; + } + int nextStartPosition = ComputeStartPosition(m_objs[next]); + // If we wrapped while placing an object, then it must be that the start position wasn't wrapped to begin with + bool isNextStartPositionWrapped = next < position && !m_isWrapped[next]; + bool isLastVacantPositionWrapped = lastVacantPosition < position; + + // We want to avoid moving objects in the cache if the next bucket position is wrapped, but the last vacant position isn't + // and we want to make sure to move objects in the cache when the last vacant position is wrapped but the next bucket position isn't + if ((nextStartPosition <= lastVacantPosition && !(isNextStartPositionWrapped && !isLastVacantPositionWrapped)) || + (isLastVacantPositionWrapped && !isNextStartPositionWrapped)) + { + m_objs[lastVacantPosition] = m_objs[next]; + m_ids[lastVacantPosition] = m_ids[next]; + // A wrapped object might become unwrapped if it moves from the front of the array to the end of the array + m_isWrapped[lastVacantPosition] = m_isWrapped[next] && next > lastVacantPosition; + lastVacantPosition = next; + } + if (next == (cacheSize - 1)) + { + next = -1; + } + } + // m_obj must ALWAYS have atleast one slot empty (null). + Fx.Assert("Object table overflow"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.ObjectTableOverflow)); + } + + private int ComputeStartPosition(object o) + { + return (RuntimeHelpers.GetHashCode(o) & 0x7FFFFFFF) % m_objs.Length; + } + + private void Rehash() + { + int size = GetPrime(m_objs.Length * 2); + int[] oldIds = m_ids; + object[] oldObjs = m_objs; + m_ids = new int[size]; + m_objs = new object[size]; + m_isWrapped = new bool[size]; + + for (int j = 0; j < oldObjs.Length; j++) + { + object obj = oldObjs[j]; + if (obj != null) + { + int position = FindElement(obj, out bool found, out bool isWrapped); + m_objs[position] = obj; + m_ids[position] = oldIds[j]; + m_isWrapped[position] = isWrapped; + } + } + } + + private static int GetPrime(int min) + { + + for (int i = 0; i < primes.Length; i++) + { + int prime = primes[i]; + if (prime >= min) + { + return prime; + } + } + + //outside of our predefined table. + //compute the hard way. + for (int i = (min | 1); i < int.MaxValue; i += 2) + { + if (IsPrime(i)) + { + return i; + } + } + return min; + } + + private static bool IsPrime(int candidate) + { + if ((candidate & 1) != 0) + { + int limit = (int)Math.Sqrt(candidate); + for (int divisor = 3; divisor <= limit; divisor += 2) + { + if ((candidate % divisor) == 0) + { + return false; + } + } + return true; + } + return (candidate == 2); + } + + internal static readonly int[] primes = + { + 3, 7, 17, 37, 89, 197, 431, 919, 1931, 4049, 8419, 17519, 36353, + 75431, 156437, 324449, 672827, 1395263, 2893249, 5999471, + }; + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/PrimitiveDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/PrimitiveDataContract.cs new file mode 100644 index 0000000..1448f03 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/PrimitiveDataContract.cs @@ -0,0 +1,837 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal abstract class PrimitiveDataContract : DataContract + { + private readonly PrimitiveDataContractCriticalHelper _helper; + + protected PrimitiveDataContract(Type type, XmlDictionaryString name, XmlDictionaryString ns) + : base(new PrimitiveDataContractCriticalHelper(type, name, ns)) + { + _helper = base.Helper as PrimitiveDataContractCriticalHelper; + } + + internal static PrimitiveDataContract GetPrimitiveDataContract(Type type) + { + return DataContract.GetBuiltInDataContract(type) as PrimitiveDataContract; + } + + internal static PrimitiveDataContract GetPrimitiveDataContract(string name, string ns) + { + return DataContract.GetBuiltInDataContract(name, ns) as PrimitiveDataContract; + } + + internal abstract string WriteMethodName { get; } + + internal abstract string ReadMethodName { get; } + + internal override XmlDictionaryString TopLevelElementNamespace + { + get => DictionaryGlobals.SerializationNamespace; + set { } + } + + internal override bool CanContainReferences => false; + + internal override bool IsPrimitive => true; + + internal override bool IsBuiltInDataContract => true; + + internal MethodInfo XmlFormatWriterMethod + { + get + { + if (_helper.XmlFormatWriterMethod == null) + { + if (UnderlyingType.IsValueType) + { + _helper.XmlFormatWriterMethod = typeof(XmlWriterDelegator).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { UnderlyingType, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); + } + else + { + _helper.XmlFormatWriterMethod = typeof(XmlObjectSerializerWriteContext).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { typeof(XmlWriterDelegator), UnderlyingType, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); + } + } + return _helper.XmlFormatWriterMethod; + } + } + + internal MethodInfo XmlFormatContentWriterMethod + { + get + { + if (_helper.XmlFormatContentWriterMethod == null) + { + if (UnderlyingType.IsValueType) + { + _helper.XmlFormatContentWriterMethod = typeof(XmlWriterDelegator).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { UnderlyingType }, null); + } + else + { + _helper.XmlFormatContentWriterMethod = typeof(XmlObjectSerializerWriteContext).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { typeof(XmlWriterDelegator), UnderlyingType }, null); + } + } + return _helper.XmlFormatContentWriterMethod; + } + } + + internal MethodInfo XmlFormatReaderMethod + { + get + { + if (_helper.XmlFormatReaderMethod == null) + { + _helper.XmlFormatReaderMethod = typeof(XmlReaderDelegator).GetMethod(ReadMethodName, Globals.ScanAllMembers); + } + return _helper.XmlFormatReaderMethod; + } + } + + public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + xmlWriter.WriteAnyType(obj); + } + + protected object HandleReadValue(object obj, XmlObjectSerializerReadContext context) + { + context.AddNewObject(obj); + return obj; + } + + protected bool TryReadNullAtTopLevel(XmlReaderDelegator reader) + { + Attributes attributes = new Attributes(); + attributes.Read(reader); + if (attributes.Ref != Globals.NewObjectId) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + XmlObjectSerializer.CreateSerializationException( + SR.Format(SR.CannotDeserializeRefAtTopLevel, attributes.Ref))); + } + + if (attributes.XsiNil) + { + reader.Skip(); + return true; + } + return false; + } + + internal override bool Equals(object other, Dictionary checkedContracts) + { + PrimitiveDataContract dataContract = other as PrimitiveDataContract; + if (dataContract != null) + { + Type thisType = GetType(); + Type otherType = other.GetType(); + return (thisType.Equals(otherType) || thisType.IsSubclassOf(otherType) || otherType.IsSubclassOf(thisType)); + } + return false; + } + + private class PrimitiveDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private MethodInfo xmlFormatWriterMethod; + private MethodInfo xmlFormatContentWriterMethod; + private MethodInfo xmlFormatReaderMethod; + + internal PrimitiveDataContractCriticalHelper(Type type, XmlDictionaryString name, XmlDictionaryString ns) + : base(type) + { + SetDataContractName(name, ns); + } + + internal MethodInfo XmlFormatWriterMethod + { + get => xmlFormatWriterMethod; + set => xmlFormatWriterMethod = value; + } + + internal MethodInfo XmlFormatContentWriterMethod + { + get => xmlFormatContentWriterMethod; + set => xmlFormatContentWriterMethod = value; + } + + internal MethodInfo XmlFormatReaderMethod + { + get => xmlFormatReaderMethod; + set => xmlFormatReaderMethod = value; + } + } + + } + + internal class CharDataContract : PrimitiveDataContract + { + internal CharDataContract() + : this(DictionaryGlobals.CharLocalName, DictionaryGlobals.SerializationNamespace) + { + } + + internal CharDataContract(XmlDictionaryString name, XmlDictionaryString ns) + : base(typeof(char), name, ns) + { + } + + internal override string WriteMethodName => "WriteChar"; + internal override string ReadMethodName => "ReadElementContentAsChar"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteChar((char)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsChar() + : HandleReadValue(reader.ReadElementContentAsChar(), context); + } + } + + internal class AsmxCharDataContract : CharDataContract + { + internal AsmxCharDataContract() : base(DictionaryGlobals.CharLocalName, DictionaryGlobals.AsmxTypesNamespace) { } + } + + internal class BooleanDataContract : PrimitiveDataContract + { + internal BooleanDataContract() + : base(typeof(bool), DictionaryGlobals.BooleanLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteBoolean"; + internal override string ReadMethodName => "ReadElementContentAsBoolean"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteBoolean((bool)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsBoolean() + : HandleReadValue(reader.ReadElementContentAsBoolean(), context); + } + } + + internal class SignedByteDataContract : PrimitiveDataContract + { + internal SignedByteDataContract() + : base(typeof(sbyte), DictionaryGlobals.SignedByteLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteSignedByte"; + internal override string ReadMethodName => "ReadElementContentAsSignedByte"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteSignedByte((sbyte)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsSignedByte() + : HandleReadValue(reader.ReadElementContentAsSignedByte(), context); + } + } + + internal class UnsignedByteDataContract : PrimitiveDataContract + { + internal UnsignedByteDataContract() + : base(typeof(byte), DictionaryGlobals.UnsignedByteLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteUnsignedByte"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedByte"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteUnsignedByte((byte)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsUnsignedByte() + : HandleReadValue(reader.ReadElementContentAsUnsignedByte(), context); + } + } + + internal class ShortDataContract : PrimitiveDataContract + { + internal ShortDataContract() + : base(typeof(short), DictionaryGlobals.ShortLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteShort"; + internal override string ReadMethodName => "ReadElementContentAsShort"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteShort((short)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsShort() + : HandleReadValue(reader.ReadElementContentAsShort(), context); + } + } + + internal class UnsignedShortDataContract : PrimitiveDataContract + { + internal UnsignedShortDataContract() + : base(typeof(ushort), DictionaryGlobals.UnsignedShortLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteUnsignedShort"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedShort"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteUnsignedShort((ushort)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsUnsignedShort() + : HandleReadValue(reader.ReadElementContentAsUnsignedShort(), context); + } + } + + internal class IntDataContract : PrimitiveDataContract + { + internal IntDataContract() + : base(typeof(int), DictionaryGlobals.IntLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteInt"; + internal override string ReadMethodName => "ReadElementContentAsInt"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteInt((int)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsInt() + : HandleReadValue(reader.ReadElementContentAsInt(), context); + } + } + + internal class UnsignedIntDataContract : PrimitiveDataContract + { + internal UnsignedIntDataContract() + : base(typeof(uint), DictionaryGlobals.UnsignedIntLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteUnsignedInt"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedInt"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteUnsignedInt((uint)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsUnsignedInt() + : HandleReadValue(reader.ReadElementContentAsUnsignedInt(), context); + } + } + + internal class LongDataContract : PrimitiveDataContract + { + internal LongDataContract() + : this(DictionaryGlobals.LongLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal LongDataContract(XmlDictionaryString name, XmlDictionaryString ns) + : base(typeof(long), name, ns) + { + } + + internal override string WriteMethodName => "WriteLong"; + internal override string ReadMethodName => "ReadElementContentAsLong"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteLong((long)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsLong() + : HandleReadValue(reader.ReadElementContentAsLong(), context); + } + } + internal class IntegerDataContract : LongDataContract + { + internal IntegerDataContract() : base(DictionaryGlobals.integerLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class PositiveIntegerDataContract : LongDataContract + { + internal PositiveIntegerDataContract() : base(DictionaryGlobals.positiveIntegerLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NegativeIntegerDataContract : LongDataContract + { + internal NegativeIntegerDataContract() : base(DictionaryGlobals.negativeIntegerLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NonPositiveIntegerDataContract : LongDataContract + { + internal NonPositiveIntegerDataContract() : base(DictionaryGlobals.nonPositiveIntegerLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NonNegativeIntegerDataContract : LongDataContract + { + internal NonNegativeIntegerDataContract() : base(DictionaryGlobals.nonNegativeIntegerLocalName, DictionaryGlobals.SchemaNamespace) { } + } + + internal class UnsignedLongDataContract : PrimitiveDataContract + { + internal UnsignedLongDataContract() + : base(typeof(ulong), DictionaryGlobals.UnsignedLongLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteUnsignedLong"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedLong"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteUnsignedLong((ulong)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsUnsignedLong() + : HandleReadValue(reader.ReadElementContentAsUnsignedLong(), context); + } + } + + internal class FloatDataContract : PrimitiveDataContract + { + internal FloatDataContract() + : base(typeof(float), DictionaryGlobals.FloatLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteFloat"; + internal override string ReadMethodName => "ReadElementContentAsFloat"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteFloat((float)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsFloat() + : HandleReadValue(reader.ReadElementContentAsFloat(), context); + } + } + + internal class DoubleDataContract : PrimitiveDataContract + { + internal DoubleDataContract() + : base(typeof(double), DictionaryGlobals.DoubleLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteDouble"; + internal override string ReadMethodName => "ReadElementContentAsDouble"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteDouble((double)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsDouble() + : HandleReadValue(reader.ReadElementContentAsDouble(), context); + } + } + + internal class DecimalDataContract : PrimitiveDataContract + { + internal DecimalDataContract() + : base(typeof(decimal), DictionaryGlobals.DecimalLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteDecimal"; + internal override string ReadMethodName => "ReadElementContentAsDecimal"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteDecimal((decimal)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsDecimal() + : HandleReadValue(reader.ReadElementContentAsDecimal(), context); + } + } + + internal class DateTimeDataContract : PrimitiveDataContract + { + internal DateTimeDataContract() + : base(typeof(DateTime), DictionaryGlobals.DateTimeLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteDateTime"; + internal override string ReadMethodName => "ReadElementContentAsDateTime"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteDateTime((DateTime)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsDateTime() + : HandleReadValue(reader.ReadElementContentAsDateTime(), context); + } + } + + internal class StringDataContract : PrimitiveDataContract + { + internal StringDataContract() + : this(DictionaryGlobals.StringLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal StringDataContract(XmlDictionaryString name, XmlDictionaryString ns) + : base(typeof(string), name, ns) + { + } + + internal override string WriteMethodName => "WriteString"; + internal override string ReadMethodName => "ReadElementContentAsString"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteString((string)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + if (context == null) + { + return TryReadNullAtTopLevel(reader) ? null : reader.ReadElementContentAsString(); + } + else + { + return HandleReadValue(reader.ReadElementContentAsString(), context); + } + } + } + internal class TimeDataContract : StringDataContract + { + internal TimeDataContract() : base(DictionaryGlobals.timeLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class DateDataContract : StringDataContract + { + internal DateDataContract() : base(DictionaryGlobals.dateLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class HexBinaryDataContract : StringDataContract + { + internal HexBinaryDataContract() : base(DictionaryGlobals.hexBinaryLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class GYearMonthDataContract : StringDataContract + { + internal GYearMonthDataContract() : base(DictionaryGlobals.gYearMonthLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class GYearDataContract : StringDataContract + { + internal GYearDataContract() : base(DictionaryGlobals.gYearLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class GMonthDayDataContract : StringDataContract + { + internal GMonthDayDataContract() : base(DictionaryGlobals.gMonthDayLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class GDayDataContract : StringDataContract + { + internal GDayDataContract() : base(DictionaryGlobals.gDayLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class GMonthDataContract : StringDataContract + { + internal GMonthDataContract() : base(DictionaryGlobals.gMonthLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NormalizedStringDataContract : StringDataContract + { + internal NormalizedStringDataContract() : base(DictionaryGlobals.normalizedStringLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class TokenDataContract : StringDataContract + { + internal TokenDataContract() : base(DictionaryGlobals.tokenLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class LanguageDataContract : StringDataContract + { + internal LanguageDataContract() : base(DictionaryGlobals.languageLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NameDataContract : StringDataContract + { + internal NameDataContract() : base(DictionaryGlobals.NameLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NCNameDataContract : StringDataContract + { + internal NCNameDataContract() : base(DictionaryGlobals.NCNameLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class IDDataContract : StringDataContract + { + internal IDDataContract() : base(DictionaryGlobals.XSDIDLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class IDREFDataContract : StringDataContract + { + internal IDREFDataContract() : base(DictionaryGlobals.IDREFLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class IDREFSDataContract : StringDataContract + { + internal IDREFSDataContract() : base(DictionaryGlobals.IDREFSLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class ENTITYDataContract : StringDataContract + { + internal ENTITYDataContract() : base(DictionaryGlobals.ENTITYLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class ENTITIESDataContract : StringDataContract + { + internal ENTITIESDataContract() : base(DictionaryGlobals.ENTITIESLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NMTOKENDataContract : StringDataContract + { + internal NMTOKENDataContract() : base(DictionaryGlobals.NMTOKENLocalName, DictionaryGlobals.SchemaNamespace) { } + } + internal class NMTOKENSDataContract : StringDataContract + { + internal NMTOKENSDataContract() : base(DictionaryGlobals.NMTOKENSLocalName, DictionaryGlobals.SchemaNamespace) { } + } + + internal class ByteArrayDataContract : PrimitiveDataContract + { + internal ByteArrayDataContract() + : base(typeof(byte[]), DictionaryGlobals.ByteArrayLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteBase64"; + internal override string ReadMethodName => "ReadElementContentAsBase64"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteBase64((byte[])obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + if (context == null) + { + return TryReadNullAtTopLevel(reader) ? null : reader.ReadElementContentAsBase64(); + } + else + { + return HandleReadValue(reader.ReadElementContentAsBase64(), context); + } + } + } + + internal class ObjectDataContract : PrimitiveDataContract + { + internal ObjectDataContract() + : base(typeof(object), DictionaryGlobals.ObjectLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteAnyType"; + internal override string ReadMethodName => "ReadElementContentAsAnyType"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + // write nothing + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + object obj; + if (reader.IsEmptyElement) + { + reader.Skip(); + obj = new object(); + } + else + { + string localName = reader.LocalName; + string ns = reader.NamespaceURI; + reader.Read(); + try + { + reader.ReadEndElement(); + obj = new object(); + } + catch (XmlException xes) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.XmlForObjectCannotHaveContent, localName, ns), xes)); + } + } + return (context == null) ? obj : HandleReadValue(obj, context); + } + + internal override bool CanContainReferences => true; + + internal override bool IsPrimitive => false; + + } + + internal class TimeSpanDataContract : PrimitiveDataContract + { + internal TimeSpanDataContract() + : this(DictionaryGlobals.TimeSpanLocalName, DictionaryGlobals.SerializationNamespace) + { + } + + internal TimeSpanDataContract(XmlDictionaryString name, XmlDictionaryString ns) + : base(typeof(TimeSpan), name, ns) + { + } + + internal override string WriteMethodName => "WriteTimeSpan"; + internal override string ReadMethodName => "ReadElementContentAsTimeSpan"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteTimeSpan((TimeSpan)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsTimeSpan() + : HandleReadValue(reader.ReadElementContentAsTimeSpan(), context); + } + } + + internal class XsDurationDataContract : TimeSpanDataContract + { + internal XsDurationDataContract() : base(DictionaryGlobals.TimeSpanLocalName, DictionaryGlobals.SchemaNamespace) { } + } + + internal class GuidDataContract : PrimitiveDataContract + { + internal GuidDataContract() + : this(DictionaryGlobals.GuidLocalName, DictionaryGlobals.SerializationNamespace) + { + } + + internal GuidDataContract(XmlDictionaryString name, XmlDictionaryString ns) + : base(typeof(Guid), name, ns) + { + } + + internal override string WriteMethodName => "WriteGuid"; + internal override string ReadMethodName => "ReadElementContentAsGuid"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteGuid((Guid)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + return (context == null) ? reader.ReadElementContentAsGuid() + : HandleReadValue(reader.ReadElementContentAsGuid(), context); + } + } + + internal class AsmxGuidDataContract : GuidDataContract + { + internal AsmxGuidDataContract() : base(DictionaryGlobals.GuidLocalName, DictionaryGlobals.AsmxTypesNamespace) { } + } + + internal class UriDataContract : PrimitiveDataContract + { + internal UriDataContract() + : base(typeof(Uri), DictionaryGlobals.UriLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteUri"; + internal override string ReadMethodName => "ReadElementContentAsUri"; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteUri((Uri)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + if (context == null) + { + return TryReadNullAtTopLevel(reader) ? null : reader.ReadElementContentAsUri(); + } + else + { + return HandleReadValue(reader.ReadElementContentAsUri(), context); + } + } + } + + internal class QNameDataContract : PrimitiveDataContract + { + internal QNameDataContract() + : base(typeof(XmlQualifiedName), DictionaryGlobals.QNameLocalName, DictionaryGlobals.SchemaNamespace) + { + } + + internal override string WriteMethodName => "WriteQName"; + internal override string ReadMethodName => "ReadElementContentAsQName"; + + internal override bool IsPrimitive => false; + + public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext context) + { + writer.WriteQName((XmlQualifiedName)obj); + } + + public override object ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext context) + { + if (context == null) + { + return TryReadNullAtTopLevel(reader) ? null : reader.ReadElementContentAsQName(); + } + else + { + return HandleReadValue(reader.ReadElementContentAsQName(), context); + } + } + + internal override void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns) + { + if (object.ReferenceEquals(ns, DictionaryGlobals.SerializationNamespace)) + { + writer.WriteStartElement(Globals.SerPrefix, name, ns); + } + else if (ns != null && ns.Value != null && ns.Value.Length > 0) + { + writer.WriteStartElement(Globals.ElementPrefix, name, ns); + } + else + { + writer.WriteStartElement(name, ns); + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaExporter.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaExporter.cs new file mode 100644 index 0000000..ebac358 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaExporter.cs @@ -0,0 +1,1194 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; + +namespace Compat.Runtime.Serialization +{ + internal class SchemaExporter + { + private XmlDocument _xmlDoc; + private DataContractSet _dataContractSet; + + internal SchemaExporter(XmlSchemaSet schemas, DataContractSet dataContractSet) + { + Schemas = schemas; + _dataContractSet = dataContractSet; + } + + private XmlSchemaSet Schemas { get; } + + private XmlDocument XmlDoc + { + get + { + if (_xmlDoc == null) + { + _xmlDoc = new XmlDocument(); + } + + return _xmlDoc; + } + } + + internal void Export() + { + try + { + // Remove this if we decide to publish serialization schema at well-known location + ExportSerializationSchema(); + foreach (KeyValuePair pair in _dataContractSet) + { + DataContract dataContract = pair.Value; + if (!_dataContractSet.IsContractProcessed(dataContract)) + { + ExportDataContract(dataContract); + _dataContractSet.SetContractProcessed(dataContract); + } + } + } + finally + { + _xmlDoc = null; + _dataContractSet = null; + } + } + + private void ExportSerializationSchema() + { + if (!Schemas.Contains(Globals.SerializationNamespace)) + { + StringReader reader = new StringReader(Globals.SerializationSchema); + XmlSchema schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); + if (schema == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace))); + } + + Schemas.Add(schema); + } + } + + private void ExportDataContract(DataContract dataContract) + { + if (dataContract.IsBuiltInDataContract) + { + return; + } + else if (dataContract is XmlDataContract) + { + ExportXmlDataContract((XmlDataContract)dataContract); + } + else + { + XmlSchema schema = GetSchema(dataContract.StableName.Namespace); + + if (dataContract is ClassDataContract) + { + ClassDataContract classDataContract = (ClassDataContract)dataContract; + if (classDataContract.IsISerializable) + { + ExportISerializableDataContract(classDataContract, schema); + } + else + { + ExportClassDataContract(classDataContract, schema); + } + } + else if (dataContract is CollectionDataContract) + { + ExportCollectionDataContract((CollectionDataContract)dataContract, schema); + } + else if (dataContract is EnumDataContract) + { + ExportEnumDataContract((EnumDataContract)dataContract, schema); + } + + ExportTopLevelElement(dataContract, schema); + Schemas.Reprocess(schema); + } + } + + private XmlSchemaElement ExportTopLevelElement(DataContract dataContract, XmlSchema schema) + { + if (schema == null || dataContract.StableName.Namespace != dataContract.TopLevelElementNamespace.Value) + { + schema = GetSchema(dataContract.TopLevelElementNamespace.Value); + } + + XmlSchemaElement topLevelElement = new XmlSchemaElement + { + Name = dataContract.TopLevelElementName.Value + }; + SetElementType(topLevelElement, dataContract, schema); + topLevelElement.IsNillable = true; + schema.Items.Add(topLevelElement); + return topLevelElement; + } + + private void ExportClassDataContract(ClassDataContract classDataContract, XmlSchema schema) + { + XmlSchemaComplexType type = new XmlSchemaComplexType + { + Name = classDataContract.StableName.Name + }; + schema.Items.Add(type); + XmlElement genericInfoElement = null; + if (classDataContract.UnderlyingType.IsGenericType) + { + genericInfoElement = ExportGenericInfo(classDataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); + } + + XmlSchemaSequence rootSequence = new XmlSchemaSequence(); + for (int i = 0; i < classDataContract.Members.Count; i++) + { + DataMember dataMember = classDataContract.Members[i]; + + XmlSchemaElement element = new XmlSchemaElement + { + Name = dataMember.Name + }; + XmlElement actualTypeElement = null; + DataContract memberTypeContract = _dataContractSet.GetMemberTypeDataContract(dataMember); + if (CheckIfMemberHasConflict(dataMember)) + { + element.SchemaTypeName = AnytypeQualifiedName; + actualTypeElement = ExportActualType(memberTypeContract.StableName); + SchemaHelper.AddSchemaImport(memberTypeContract.StableName.Namespace, schema); + } + else + { + SetElementType(element, memberTypeContract, schema); + } + + SchemaHelper.AddElementForm(element, schema); + if (dataMember.IsNullable) + { + element.IsNillable = true; + } + + if (!dataMember.IsRequired) + { + element.MinOccurs = 0; + } + + element.Annotation = GetSchemaAnnotation(actualTypeElement, ExportSurrogateData(dataMember), ExportEmitDefaultValue(dataMember)); + rootSequence.Items.Add(element); + } + + XmlElement isValueTypeElement = null; + if (classDataContract.BaseContract != null) + { + XmlSchemaComplexContentExtension extension = CreateTypeContent(type, classDataContract.BaseContract.StableName, schema); + extension.Particle = rootSequence; + if (classDataContract.IsReference && !classDataContract.BaseContract.IsReference) + { + AddReferenceAttributes(extension.Attributes, schema); + } + } + else + { + type.Particle = rootSequence; + if (classDataContract.IsValueType) + { + isValueTypeElement = GetAnnotationMarkup(IsValueTypeName, XmlConvert.ToString(classDataContract.IsValueType), schema); + } + + if (classDataContract.IsReference) + { + AddReferenceAttributes(type.Attributes, schema); + } + } + type.Annotation = GetSchemaAnnotation(genericInfoElement, ExportSurrogateData(classDataContract), isValueTypeElement); + } + + private void AddReferenceAttributes(XmlSchemaObjectCollection attributes, XmlSchema schema) + { + SchemaHelper.AddSchemaImport(Globals.SerializationNamespace, schema); + schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); + attributes.Add(IdAttribute); + attributes.Add(RefAttribute); + } + + private void SetElementType(XmlSchemaElement element, DataContract dataContract, XmlSchema schema) + { + XmlDataContract xmlDataContract = dataContract as XmlDataContract; + if (xmlDataContract != null && xmlDataContract.IsAnonymous) + { + element.SchemaType = xmlDataContract.XsdType; + } + else + { + element.SchemaTypeName = dataContract.StableName; + + if (element.SchemaTypeName.Namespace.Equals(Globals.SerializationNamespace)) + { + schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); + } + + SchemaHelper.AddSchemaImport(dataContract.StableName.Namespace, schema); + } + } + + private bool CheckIfMemberHasConflict(DataMember dataMember) + { + if (dataMember.HasConflictingNameAndType) + { + return true; + } + + DataMember conflictingMember = dataMember.ConflictingMember; + while (conflictingMember != null) + { + if (conflictingMember.HasConflictingNameAndType) + { + return true; + } + + conflictingMember = conflictingMember.ConflictingMember; + } + + return false; + } + + private XmlElement ExportEmitDefaultValue(DataMember dataMember) + { + if (dataMember.EmitDefaultValue) + { + return null; + } + + XmlElement defaultValueElement = XmlDoc.CreateElement(DefaultValueAnnotation.Name, DefaultValueAnnotation.Namespace); + XmlAttribute emitDefaultValueAttribute = XmlDoc.CreateAttribute(Globals.EmitDefaultValueAttribute); + emitDefaultValueAttribute.Value = Globals.False; + defaultValueElement.Attributes.Append(emitDefaultValueAttribute); + return defaultValueElement; + + } + + private XmlElement ExportActualType(XmlQualifiedName typeName) + { + return ExportActualType(typeName, XmlDoc); + } + + private static XmlElement ExportActualType(XmlQualifiedName typeName, XmlDocument xmlDoc) + { + XmlElement actualTypeElement = xmlDoc.CreateElement(ActualTypeAnnotationName.Name, ActualTypeAnnotationName.Namespace); + + XmlAttribute nameAttribute = xmlDoc.CreateAttribute(Globals.ActualTypeNameAttribute); + nameAttribute.Value = typeName.Name; + actualTypeElement.Attributes.Append(nameAttribute); + + XmlAttribute nsAttribute = xmlDoc.CreateAttribute(Globals.ActualTypeNamespaceAttribute); + nsAttribute.Value = typeName.Namespace; + actualTypeElement.Attributes.Append(nsAttribute); + + return actualTypeElement; + } + + private XmlElement ExportGenericInfo(Type clrType, string elementName, string elementNs) + { + int nestedCollectionLevel = 0; + while (CollectionDataContract.IsCollection(clrType, out Type itemType)) + { + if (DataContract.GetBuiltInDataContract(clrType) != null + || CollectionDataContract.IsCollectionDataContract(clrType)) + { + break; + } + clrType = itemType; + nestedCollectionLevel++; + } + + Type[] genericArguments = null; + IList genericArgumentCounts = null; + if (clrType.IsGenericType) + { + genericArguments = clrType.GetGenericArguments(); + string typeName; + if (clrType.DeclaringType == null) + { + typeName = clrType.Name; + } + else + { + int nsLen = (clrType.Namespace == null) ? 0 : clrType.Namespace.Length; + if (nsLen > 0) + { + nsLen++; //include the . following namespace + } + + typeName = DataContract.GetClrTypeFullName(clrType).Substring(nsLen).Replace('+', '.'); + } + int iParam = typeName.IndexOf('['); + if (iParam >= 0) + { + typeName = typeName.Substring(0, iParam); + } + + genericArgumentCounts = DataContract.GetDataContractNameForGenericName(typeName, null); + clrType = clrType.GetGenericTypeDefinition(); + } + XmlQualifiedName dcqname = DataContract.GetStableName(clrType); + if (nestedCollectionLevel > 0) + { + string collectionName = dcqname.Name; + for (int n = 0; n < nestedCollectionLevel; n++) + { + collectionName = Globals.ArrayPrefix + collectionName; + } + + dcqname = new XmlQualifiedName(collectionName, DataContract.GetCollectionNamespace(dcqname.Namespace)); + } + XmlElement typeElement = XmlDoc.CreateElement(elementName, elementNs); + + XmlAttribute nameAttribute = XmlDoc.CreateAttribute(Globals.GenericNameAttribute); + nameAttribute.Value = genericArguments != null ? XmlConvert.DecodeName(dcqname.Name) : dcqname.Name; + //nameAttribute.Value = dcqname.Name; + typeElement.Attributes.Append(nameAttribute); + + XmlAttribute nsAttribute = XmlDoc.CreateAttribute(Globals.GenericNamespaceAttribute); + nsAttribute.Value = dcqname.Namespace; + typeElement.Attributes.Append(nsAttribute); + + if (genericArguments != null) + { + int argIndex = 0; + int nestedLevel = 0; + foreach (int genericArgumentCount in genericArgumentCounts) + { + for (int i = 0; i < genericArgumentCount; i++, argIndex++) + { + XmlElement argumentElement = ExportGenericInfo(genericArguments[argIndex], Globals.GenericParameterLocalName, Globals.SerializationNamespace); + if (nestedLevel > 0) + { + XmlAttribute nestedLevelAttribute = XmlDoc.CreateAttribute(Globals.GenericParameterNestedLevelAttribute); + nestedLevelAttribute.Value = nestedLevel.ToString(CultureInfo.InvariantCulture); + argumentElement.Attributes.Append(nestedLevelAttribute); + } + typeElement.AppendChild(argumentElement); + } + nestedLevel++; + } + if (genericArgumentCounts[nestedLevel - 1] == 0) + { + XmlAttribute typeNestedLevelsAttribute = XmlDoc.CreateAttribute(Globals.GenericParameterNestedLevelAttribute); + typeNestedLevelsAttribute.Value = genericArgumentCounts.Count.ToString(CultureInfo.InvariantCulture); + typeElement.Attributes.Append(typeNestedLevelsAttribute); + } + } + + return typeElement; + } + + private XmlElement ExportSurrogateData(object key) + { + object surrogateData = _dataContractSet.GetSurrogateData(key); + if (surrogateData == null) + { + return null; + } + + StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); + XmlWriterSettings writerSettings = new XmlWriterSettings + { + OmitXmlDeclaration = true + }; + XmlWriter xmlWriter = XmlWriter.Create(stringWriter, writerSettings); + Collection knownTypes = new Collection(); + DataContractSurrogateCaller.GetKnownCustomDataTypes(_dataContractSet.DataContractSurrogate, knownTypes); + DataContractSerializer serializer = new DataContractSerializer(Globals.TypeOfObject, + SurrogateDataAnnotationName.Name, SurrogateDataAnnotationName.Namespace, knownTypes, int.MaxValue, + false /*ignoreExtensionDataObject*/, true /*preserveObjectReferences*/, null /*dataContractSurrogate*/); + serializer.WriteObject(xmlWriter, surrogateData); + xmlWriter.Flush(); + return (XmlElement)XmlDoc.ReadNode(XmlReader.Create(new StringReader(stringWriter.ToString()))); + } + + private void ExportCollectionDataContract(CollectionDataContract collectionDataContract, XmlSchema schema) + { + XmlSchemaComplexType type = new XmlSchemaComplexType + { + Name = collectionDataContract.StableName.Name + }; + schema.Items.Add(type); + XmlElement genericInfoElement = null, isDictionaryElement = null; + if (collectionDataContract.UnderlyingType.IsGenericType && CollectionDataContract.IsCollectionDataContract(collectionDataContract.UnderlyingType)) + { + genericInfoElement = ExportGenericInfo(collectionDataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); + } + + if (collectionDataContract.IsDictionary) + { + isDictionaryElement = ExportIsDictionary(); + } + + type.Annotation = GetSchemaAnnotation(isDictionaryElement, genericInfoElement, ExportSurrogateData(collectionDataContract)); + + XmlSchemaSequence rootSequence = new XmlSchemaSequence(); + + XmlSchemaElement element = new XmlSchemaElement + { + Name = collectionDataContract.ItemName, + MinOccurs = 0, + MaxOccursString = Globals.OccursUnbounded + }; + if (collectionDataContract.IsDictionary) + { + ClassDataContract keyValueContract = collectionDataContract.ItemContract as ClassDataContract; + XmlSchemaComplexType keyValueType = new XmlSchemaComplexType(); + XmlSchemaSequence keyValueSequence = new XmlSchemaSequence(); + foreach (DataMember dataMember in keyValueContract.Members) + { + XmlSchemaElement keyValueElement = new XmlSchemaElement + { + Name = dataMember.Name + }; + SetElementType(keyValueElement, _dataContractSet.GetMemberTypeDataContract(dataMember), schema); + SchemaHelper.AddElementForm(keyValueElement, schema); + if (dataMember.IsNullable) + { + keyValueElement.IsNillable = true; + } + + keyValueElement.Annotation = GetSchemaAnnotation(ExportSurrogateData(dataMember)); + keyValueSequence.Items.Add(keyValueElement); + } + keyValueType.Particle = keyValueSequence; + element.SchemaType = keyValueType; + } + else + { + if (collectionDataContract.IsItemTypeNullable) + { + element.IsNillable = true; + } + + DataContract itemContract = _dataContractSet.GetItemTypeDataContract(collectionDataContract); + SetElementType(element, itemContract, schema); + } + SchemaHelper.AddElementForm(element, schema); + rootSequence.Items.Add(element); + + type.Particle = rootSequence; + + if (collectionDataContract.IsReference) + { + AddReferenceAttributes(type.Attributes, schema); + } + } + + private XmlElement ExportIsDictionary() + { + XmlElement isDictionaryElement = XmlDoc.CreateElement(IsDictionaryAnnotationName.Name, IsDictionaryAnnotationName.Namespace); + isDictionaryElement.InnerText = Globals.True; + return isDictionaryElement; + } + + private void ExportEnumDataContract(EnumDataContract enumDataContract, XmlSchema schema) + { + XmlSchemaSimpleType type = new XmlSchemaSimpleType + { + Name = enumDataContract.StableName.Name + }; + XmlElement actualTypeElement = (enumDataContract.BaseContractName == DefaultEnumBaseTypeName) ? null : ExportActualType(enumDataContract.BaseContractName); + type.Annotation = GetSchemaAnnotation(actualTypeElement, ExportSurrogateData(enumDataContract)); + schema.Items.Add(type); + + XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction + { + BaseTypeName = StringQualifiedName + }; + SchemaHelper.AddSchemaImport(enumDataContract.BaseContractName.Namespace, schema); + if (enumDataContract.Values != null) + { + for (int i = 0; i < enumDataContract.Values.Count; i++) + { + XmlSchemaEnumerationFacet facet = new XmlSchemaEnumerationFacet + { + Value = enumDataContract.Members[i].Name + }; + if (enumDataContract.Values[i] != GetDefaultEnumValue(enumDataContract.IsFlags, i)) + { + facet.Annotation = GetSchemaAnnotation(EnumerationValueAnnotationName, enumDataContract.GetStringFromEnumValue(enumDataContract.Values[i]), schema); + } + + restriction.Facets.Add(facet); + } + } + if (enumDataContract.IsFlags) + { + XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList(); + XmlSchemaSimpleType anonymousType = new XmlSchemaSimpleType + { + Content = restriction + }; + list.ItemType = anonymousType; + type.Content = list; + } + else + { + type.Content = restriction; + } + } + + internal static long GetDefaultEnumValue(bool isFlags, int index) + { + return isFlags ? (long)Math.Pow(2, index) : index; + } + + private void ExportISerializableDataContract(ClassDataContract dataContract, XmlSchema schema) + { + XmlSchemaComplexType type = new XmlSchemaComplexType + { + Name = dataContract.StableName.Name + }; + schema.Items.Add(type); + XmlElement genericInfoElement = null; + if (dataContract.UnderlyingType.IsGenericType) + { + genericInfoElement = ExportGenericInfo(dataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); + } + + XmlElement isValueTypeElement = null; + if (dataContract.BaseContract != null) + { + XmlSchemaComplexContentExtension extension = CreateTypeContent(type, dataContract.BaseContract.StableName, schema); + } + else + { + schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); + type.Particle = ISerializableSequence; + XmlSchemaAttribute iSerializableFactoryTypeAttribute = ISerializableFactoryTypeAttribute; + type.Attributes.Add(iSerializableFactoryTypeAttribute); + SchemaHelper.AddSchemaImport(ISerializableFactoryTypeAttribute.RefName.Namespace, schema); + if (dataContract.IsValueType) + { + isValueTypeElement = GetAnnotationMarkup(IsValueTypeName, XmlConvert.ToString(dataContract.IsValueType), schema); + } + } + type.Annotation = GetSchemaAnnotation(genericInfoElement, ExportSurrogateData(dataContract), isValueTypeElement); + } + + private XmlSchemaComplexContentExtension CreateTypeContent(XmlSchemaComplexType type, XmlQualifiedName baseTypeName, XmlSchema schema) + { + SchemaHelper.AddSchemaImport(baseTypeName.Namespace, schema); + + XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension + { + BaseTypeName = baseTypeName + }; + type.ContentModel = new XmlSchemaComplexContent + { + Content = extension + }; + + return extension; + } + + private void ExportXmlDataContract(XmlDataContract dataContract) + { + + Type clrType = dataContract.UnderlyingType; + if (!IsSpecialXmlType(clrType, out XmlQualifiedName typeQName, out XmlSchemaType xsdType, out bool hasRoot)) + { + if (!InvokeSchemaProviderMethod(clrType, Schemas, out typeQName, out xsdType, out hasRoot)) + { + InvokeGetSchemaMethod(clrType, Schemas, typeQName); + } + } + + if (hasRoot) + { + if (!(typeQName.Equals(dataContract.StableName))) + { + Fx.Assert("XML data contract type name does not match schema name"); + } + + if (SchemaHelper.GetSchemaElement(Schemas, + new XmlQualifiedName(dataContract.TopLevelElementName.Value, dataContract.TopLevelElementNamespace.Value), + out XmlSchema schema) == null) + { + XmlSchemaElement topLevelElement = ExportTopLevelElement(dataContract, schema); + topLevelElement.IsNillable = dataContract.IsTopLevelElementNullable; + ReprocessAll(Schemas); + } + + XmlSchemaType anonymousType = xsdType; + xsdType = SchemaHelper.GetSchemaType(Schemas, typeQName, out schema); + if (anonymousType == null && xsdType == null && typeQName.Namespace != XmlSchema.Namespace) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.MissingSchemaType, typeQName, DataContract.GetClrTypeFullName(clrType)))); + } + if (xsdType != null) + { + xsdType.Annotation = GetSchemaAnnotation( + ExportSurrogateData(dataContract), + dataContract.IsValueType ? + GetAnnotationMarkup(IsValueTypeName, XmlConvert.ToString(dataContract.IsValueType), schema) : + null + ); + } + } + } + + private static void ReprocessAll(XmlSchemaSet schemas)// and remove duplicate items + { + Hashtable elements = new Hashtable(); + Hashtable types = new Hashtable(); + XmlSchema[] schemaArray = new XmlSchema[schemas.Count]; + schemas.CopyTo(schemaArray, 0); + for (int i = 0; i < schemaArray.Length; i++) + { + XmlSchema schema = schemaArray[i]; + XmlSchemaObject[] itemArray = new XmlSchemaObject[schema.Items.Count]; + schema.Items.CopyTo(itemArray, 0); + for (int j = 0; j < itemArray.Length; j++) + { + XmlSchemaObject item = itemArray[j]; + Hashtable items; + XmlQualifiedName qname; + if (item is XmlSchemaElement) + { + items = elements; + qname = new XmlQualifiedName(((XmlSchemaElement)item).Name, schema.TargetNamespace); + } + else if (item is XmlSchemaType) + { + items = types; + qname = new XmlQualifiedName(((XmlSchemaType)item).Name, schema.TargetNamespace); + } + else + { + continue; + } + + object otherItem = items[qname]; + if (otherItem != null) + { + schema.Items.Remove(item); + } + else + { + items.Add(qname, item); + } + } + schemas.Reprocess(schema); + } + } + + internal static void GetXmlTypeInfo(Type type, out XmlQualifiedName stableName, out XmlSchemaType xsdType, out bool hasRoot) + { + if (IsSpecialXmlType(type, out stableName, out xsdType, out hasRoot)) + { + return; + } + + XmlSchemaSet schemas = new XmlSchemaSet + { + XmlResolver = null + }; + InvokeSchemaProviderMethod(type, schemas, out stableName, out xsdType, out hasRoot); + if (stableName.Name == null || stableName.Name.Length == 0) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidXmlDataContractName, DataContract.GetClrTypeFullName(type)))); + } + } + + private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schemas, out XmlQualifiedName stableName, out XmlSchemaType xsdType, out bool hasRoot) + { + xsdType = null; + hasRoot = true; + object[] attrs = clrType.GetCustomAttributes(Globals.TypeOfXmlSchemaProviderAttribute, false); + if (attrs == null || attrs.Length == 0) + { + stableName = DataContract.GetDefaultStableName(clrType); + return false; + } + + XmlSchemaProviderAttribute provider = (XmlSchemaProviderAttribute)attrs[0]; + if (provider.IsAny) + { + xsdType = CreateAnyElementType(); + hasRoot = false; + } + string methodName = provider.MethodName; + if (methodName == null || methodName.Length == 0) + { + if (!provider.IsAny) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidGetSchemaMethod, DataContract.GetClrTypeFullName(clrType)))); + } + + stableName = DataContract.GetDefaultStableName(clrType); + } + else + { + MethodInfo getMethod = clrType.GetMethod(methodName, /*BindingFlags.DeclaredOnly |*/ BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { typeof(XmlSchemaSet) }, null); + if (getMethod == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.MissingGetSchemaMethod, DataContract.GetClrTypeFullName(clrType), methodName))); + } + + if (!(Globals.TypeOfXmlQualifiedName.IsAssignableFrom(getMethod.ReturnType)) && !(Globals.TypeOfXmlSchemaType.IsAssignableFrom(getMethod.ReturnType))) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidReturnTypeOnGetSchemaMethod, DataContract.GetClrTypeFullName(clrType), methodName, DataContract.GetClrTypeFullName(getMethod.ReturnType), DataContract.GetClrTypeFullName(Globals.TypeOfXmlQualifiedName), typeof(XmlSchemaType)))); + } + + object typeInfo = getMethod.Invoke(null, new object[] { schemas }); + + if (provider.IsAny) + { + if (typeInfo != null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidNonNullReturnValueByIsAny, DataContract.GetClrTypeFullName(clrType), methodName))); + } + + stableName = DataContract.GetDefaultStableName(clrType); + } + else if (typeInfo == null) + { + xsdType = CreateAnyElementType(); + hasRoot = false; + stableName = DataContract.GetDefaultStableName(clrType); + } + else + { + XmlSchemaType providerXsdType = typeInfo as XmlSchemaType; + if (providerXsdType != null) + { + string typeName = providerXsdType.Name; + string typeNs = null; + if (typeName == null || typeName.Length == 0) + { + DataContract.GetDefaultStableName(DataContract.GetClrTypeFullName(clrType), out typeName, out typeNs); + stableName = new XmlQualifiedName(typeName, typeNs); + providerXsdType.Annotation = GetSchemaAnnotation(ExportActualType(stableName, new XmlDocument())); + xsdType = providerXsdType; + } + else + { + foreach (XmlSchema schema in schemas.Schemas()) + { + foreach (XmlSchemaObject schemaItem in schema.Items) + { + if (schemaItem == (object)providerXsdType) + { + typeNs = schema.TargetNamespace; + if (typeNs == null) + { + typeNs = string.Empty; + } + + break; + } + } + if (typeNs != null) + { + break; + } + } + if (typeNs == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.MissingSchemaType, typeName, DataContract.GetClrTypeFullName(clrType)))); + } + + stableName = new XmlQualifiedName(typeName, typeNs); + } + } + else + { + stableName = (XmlQualifiedName)typeInfo; + } + } + } + return true; + } + + private static void InvokeGetSchemaMethod(Type clrType, XmlSchemaSet schemas, XmlQualifiedName stableName) + { + IXmlSerializable ixmlSerializable = (IXmlSerializable)Activator.CreateInstance(clrType); + XmlSchema schema = ixmlSerializable.GetSchema(); + if (schema == null) + { + AddDefaultDatasetType(schemas, stableName.Name, stableName.Namespace); + } + else + { + if (schema.Id == null || schema.Id.Length == 0) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidReturnSchemaOnGetSchemaMethod, DataContract.GetClrTypeFullName(clrType)))); + } + + AddDefaultTypedDatasetType(schemas, schema, stableName.Name, stableName.Namespace); + } + } + + internal static void AddDefaultXmlType(XmlSchemaSet schemas, string localName, string ns) + { + XmlSchemaComplexType defaultXmlType = CreateAnyType(); + defaultXmlType.Name = localName; + XmlSchema schema = SchemaHelper.GetSchema(ns, schemas); + schema.Items.Add(defaultXmlType); + schemas.Reprocess(schema); + } + + private static XmlSchemaComplexType CreateAnyType() + { + XmlSchemaComplexType anyType = new XmlSchemaComplexType + { + IsMixed = true, + Particle = new XmlSchemaSequence() + }; + XmlSchemaAny any = new XmlSchemaAny + { + MinOccurs = 0, + MaxOccurs = decimal.MaxValue, + ProcessContents = XmlSchemaContentProcessing.Lax + }; + ((XmlSchemaSequence)anyType.Particle).Items.Add(any); + anyType.AnyAttribute = new XmlSchemaAnyAttribute(); + return anyType; + } + + private static XmlSchemaComplexType CreateAnyElementType() + { + XmlSchemaComplexType anyElementType = new XmlSchemaComplexType + { + IsMixed = false, + Particle = new XmlSchemaSequence() + }; + XmlSchemaAny any = new XmlSchemaAny + { + MinOccurs = 0, + ProcessContents = XmlSchemaContentProcessing.Lax + }; + ((XmlSchemaSequence)anyElementType.Particle).Items.Add(any); + return anyElementType; + } + + internal static bool IsSpecialXmlType(Type type, out XmlQualifiedName typeName, out XmlSchemaType xsdType, out bool hasRoot) + { + xsdType = null; + hasRoot = true; + if (type == Globals.TypeOfXmlElement || type == Globals.TypeOfXmlNodeArray) + { + string name = null; + if (type == Globals.TypeOfXmlElement) + { + xsdType = CreateAnyElementType(); + name = "XmlElement"; + hasRoot = false; + } + else + { + xsdType = CreateAnyType(); + name = "ArrayOfXmlNode"; + hasRoot = true; + } + typeName = new XmlQualifiedName(name, DataContract.GetDefaultStableNamespace(type)); + return true; + } + typeName = null; + return false; + } + + private static void AddDefaultDatasetType(XmlSchemaSet schemas, string localName, string ns) + { + XmlSchemaComplexType type = new XmlSchemaComplexType + { + Name = localName, + Particle = new XmlSchemaSequence() + }; + XmlSchemaElement schemaRefElement = new XmlSchemaElement + { + RefName = new XmlQualifiedName(Globals.SchemaLocalName, XmlSchema.Namespace) + }; + ((XmlSchemaSequence)type.Particle).Items.Add(schemaRefElement); + XmlSchemaAny any = new XmlSchemaAny(); + ((XmlSchemaSequence)type.Particle).Items.Add(any); + XmlSchema schema = SchemaHelper.GetSchema(ns, schemas); + schema.Items.Add(type); + schemas.Reprocess(schema); + } + + private static void AddDefaultTypedDatasetType(XmlSchemaSet schemas, XmlSchema datasetSchema, string localName, string ns) + { + XmlSchemaComplexType type = new XmlSchemaComplexType + { + Name = localName, + Particle = new XmlSchemaSequence() + }; + XmlSchemaAny any = new XmlSchemaAny + { + Namespace = (datasetSchema.TargetNamespace == null) ? string.Empty : datasetSchema.TargetNamespace + }; + ((XmlSchemaSequence)type.Particle).Items.Add(any); + schemas.Add(datasetSchema); + XmlSchema schema = SchemaHelper.GetSchema(ns, schemas); + schema.Items.Add(type); + schemas.Reprocess(datasetSchema); + schemas.Reprocess(schema); + } + + private XmlSchemaAnnotation GetSchemaAnnotation(XmlQualifiedName annotationQualifiedName, string innerText, XmlSchema schema) + { + XmlSchemaAnnotation annotation = new XmlSchemaAnnotation(); + XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo(); + XmlElement annotationElement = GetAnnotationMarkup(annotationQualifiedName, innerText, schema); + appInfo.Markup = new XmlNode[1] { annotationElement }; + annotation.Items.Add(appInfo); + return annotation; + } + + private static XmlSchemaAnnotation GetSchemaAnnotation(params XmlNode[] nodes) + { + if (nodes == null || nodes.Length == 0) + { + return null; + } + + bool hasAnnotation = false; + for (int i = 0; i < nodes.Length; i++) + { + if (nodes[i] != null) + { + hasAnnotation = true; + break; + } + } + + if (!hasAnnotation) + { + return null; + } + + XmlSchemaAnnotation annotation = new XmlSchemaAnnotation(); + XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo(); + annotation.Items.Add(appInfo); + appInfo.Markup = nodes; + return annotation; + } + + private XmlElement GetAnnotationMarkup(XmlQualifiedName annotationQualifiedName, string innerText, XmlSchema schema) + { + XmlElement annotationElement = XmlDoc.CreateElement(annotationQualifiedName.Name, annotationQualifiedName.Namespace); + SchemaHelper.AddSchemaImport(annotationQualifiedName.Namespace, schema); + annotationElement.InnerText = innerText; + return annotationElement; + } + + private XmlSchema GetSchema(string ns) + { + return SchemaHelper.GetSchema(ns, Schemas); + } + + // Property is not stored in a local because XmlSchemaSequence is mutable. + // The schema export process should not expose objects that may be modified later. + internal static XmlSchemaSequence ISerializableSequence + { + get + { + XmlSchemaSequence iSerializableSequence = new XmlSchemaSequence(); + iSerializableSequence.Items.Add(ISerializableWildcardElement); + return iSerializableSequence; + } + } + + // Property is not stored in a local because XmlSchemaAny is mutable. + // The schema export process should not expose objects that may be modified later. + internal static XmlSchemaAny ISerializableWildcardElement + { + get + { + XmlSchemaAny iSerializableWildcardElement = new XmlSchemaAny + { + MinOccurs = 0, + MaxOccursString = Globals.OccursUnbounded, + Namespace = "##local", + ProcessContents = XmlSchemaContentProcessing.Skip + }; + return iSerializableWildcardElement; + } + } + + private static XmlQualifiedName anytypeQualifiedName; + internal static XmlQualifiedName AnytypeQualifiedName + { + get + { + if (anytypeQualifiedName == null) + { + anytypeQualifiedName = new XmlQualifiedName(Globals.AnyTypeLocalName, Globals.SchemaNamespace); + } + + return anytypeQualifiedName; + } + } + + private static XmlQualifiedName stringQualifiedName; + internal static XmlQualifiedName StringQualifiedName + { + get + { + if (stringQualifiedName == null) + { + stringQualifiedName = new XmlQualifiedName(Globals.StringLocalName, Globals.SchemaNamespace); + } + + return stringQualifiedName; + } + } + + private static XmlQualifiedName defaultEnumBaseTypeName; + internal static XmlQualifiedName DefaultEnumBaseTypeName + { + get + { + if (defaultEnumBaseTypeName == null) + { + defaultEnumBaseTypeName = new XmlQualifiedName(Globals.IntLocalName, Globals.SchemaNamespace); + } + + return defaultEnumBaseTypeName; + } + } + + private static XmlQualifiedName enumerationValueAnnotationName; + internal static XmlQualifiedName EnumerationValueAnnotationName + { + get + { + if (enumerationValueAnnotationName == null) + { + enumerationValueAnnotationName = new XmlQualifiedName(Globals.EnumerationValueLocalName, Globals.SerializationNamespace); + } + + return enumerationValueAnnotationName; + } + } + + private static XmlQualifiedName surrogateDataAnnotationName; + internal static XmlQualifiedName SurrogateDataAnnotationName + { + get + { + if (surrogateDataAnnotationName == null) + { + surrogateDataAnnotationName = new XmlQualifiedName(Globals.SurrogateDataLocalName, Globals.SerializationNamespace); + } + + return surrogateDataAnnotationName; + } + } + + private static XmlQualifiedName defaultValueAnnotation; + internal static XmlQualifiedName DefaultValueAnnotation + { + get + { + if (defaultValueAnnotation == null) + { + defaultValueAnnotation = new XmlQualifiedName(Globals.DefaultValueLocalName, Globals.SerializationNamespace); + } + + return defaultValueAnnotation; + } + } + + private static XmlQualifiedName actualTypeAnnotationName; + internal static XmlQualifiedName ActualTypeAnnotationName + { + get + { + if (actualTypeAnnotationName == null) + { + actualTypeAnnotationName = new XmlQualifiedName(Globals.ActualTypeLocalName, Globals.SerializationNamespace); + } + + return actualTypeAnnotationName; + } + } + + private static XmlQualifiedName isDictionaryAnnotationName; + internal static XmlQualifiedName IsDictionaryAnnotationName + { + get + { + if (isDictionaryAnnotationName == null) + { + isDictionaryAnnotationName = new XmlQualifiedName(Globals.IsDictionaryLocalName, Globals.SerializationNamespace); + } + + return isDictionaryAnnotationName; + } + } + + private static XmlQualifiedName isValueTypeName; + internal static XmlQualifiedName IsValueTypeName + { + get + { + if (isValueTypeName == null) + { + isValueTypeName = new XmlQualifiedName(Globals.IsValueTypeLocalName, Globals.SerializationNamespace); + } + + return isValueTypeName; + } + } + + // Property is not stored in a local because XmlSchemaAttribute is mutable. + // The schema export process should not expose objects that may be modified later. + internal static XmlSchemaAttribute ISerializableFactoryTypeAttribute + { + get + { + XmlSchemaAttribute iSerializableFactoryTypeAttribute = new XmlSchemaAttribute + { + RefName = new XmlQualifiedName(Globals.ISerializableFactoryTypeLocalName, Globals.SerializationNamespace) + }; + return iSerializableFactoryTypeAttribute; + } + } + + // Property is not stored in a local because XmlSchemaAttribute is mutable. + // The schema export process should not expose objects that may be modified later. + internal static XmlSchemaAttribute RefAttribute + { + get + { + XmlSchemaAttribute refAttribute = new XmlSchemaAttribute + { + RefName = Globals.RefQualifiedName + }; + return refAttribute; + } + } + + // Property is not stored in a local because XmlSchemaAttribute is mutable. + // The schema export process should not expose objects that may be modified later. + internal static XmlSchemaAttribute IdAttribute + { + get + { + XmlSchemaAttribute idAttribute = new XmlSchemaAttribute + { + RefName = Globals.IdQualifiedName + }; + return idAttribute; + } + } + } +} + diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaHelper.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaHelper.cs new file mode 100644 index 0000000..465a512 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaHelper.cs @@ -0,0 +1,246 @@ +using System.Collections; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Schema; + +namespace Compat.Runtime.Serialization +{ + using SchemaObjectDictionary = Dictionary; + + internal class SchemaObjectInfo + { + internal XmlSchemaType type; + internal XmlSchemaElement element; + internal XmlSchema schema; + internal List knownTypes; + + internal SchemaObjectInfo(XmlSchemaType type, XmlSchemaElement element, XmlSchema schema, List knownTypes) + { + this.type = type; + this.element = element; + this.schema = schema; + this.knownTypes = knownTypes; + } + } + + internal static class SchemaHelper + { + + internal static bool NamespacesEqual(string ns1, string ns2) + { + if (ns1 == null || ns1.Length == 0) + { + return (ns2 == null || ns2.Length == 0); + } + else + { + return ns1 == ns2; + } + } + + internal static XmlSchemaType GetSchemaType(XmlSchemaSet schemas, XmlQualifiedName typeQName, out XmlSchema outSchema) + { + outSchema = null; + ICollection currentSchemas = schemas.Schemas(); + string ns = typeQName.Namespace; + foreach (XmlSchema schema in currentSchemas) + { + if (NamespacesEqual(ns, schema.TargetNamespace)) + { + outSchema = schema; + foreach (XmlSchemaObject schemaObj in schema.Items) + { + XmlSchemaType schemaType = schemaObj as XmlSchemaType; + if (schemaType != null && schemaType.Name == typeQName.Name) + { + return schemaType; + } + } + } + } + return null; + } + + internal static XmlSchemaType GetSchemaType(SchemaObjectDictionary schemaInfo, XmlQualifiedName typeName) + { + if (schemaInfo.TryGetValue(typeName, out SchemaObjectInfo schemaObjectInfo)) + { + return schemaObjectInfo.type; + } + return null; + } + + internal static XmlSchema GetSchemaWithType(SchemaObjectDictionary schemaInfo, XmlSchemaSet schemas, XmlQualifiedName typeName) + { + if (schemaInfo.TryGetValue(typeName, out SchemaObjectInfo schemaObjectInfo)) + { + if (schemaObjectInfo.schema != null) + { + return schemaObjectInfo.schema; + } + } + ICollection currentSchemas = schemas.Schemas(); + string ns = typeName.Namespace; + foreach (XmlSchema schema in currentSchemas) + { + if (NamespacesEqual(ns, schema.TargetNamespace)) + { + return schema; + } + } + return null; + } + + internal static XmlSchemaElement GetSchemaElement(XmlSchemaSet schemas, XmlQualifiedName elementQName, out XmlSchema outSchema) + { + outSchema = null; + ICollection currentSchemas = schemas.Schemas(); + string ns = elementQName.Namespace; + foreach (XmlSchema schema in currentSchemas) + { + if (NamespacesEqual(ns, schema.TargetNamespace)) + { + outSchema = schema; + foreach (XmlSchemaObject schemaObj in schema.Items) + { + XmlSchemaElement schemaElement = schemaObj as XmlSchemaElement; + if (schemaElement != null && schemaElement.Name == elementQName.Name) + { + return schemaElement; + } + } + } + } + return null; + } + + internal static XmlSchemaElement GetSchemaElement(SchemaObjectDictionary schemaInfo, XmlQualifiedName elementName) + { + if (schemaInfo.TryGetValue(elementName, out SchemaObjectInfo schemaObjectInfo)) + { + return schemaObjectInfo.element; + } + return null; + } + + internal static XmlSchema GetSchema(string ns, XmlSchemaSet schemas) + { + if (ns == null) { ns = string.Empty; } + + ICollection currentSchemas = schemas.Schemas(); + foreach (XmlSchema schema in currentSchemas) + { + if ((schema.TargetNamespace == null && ns.Length == 0) || ns.Equals(schema.TargetNamespace)) + { + return schema; + } + } + return CreateSchema(ns, schemas); + } + + private static XmlSchema CreateSchema(string ns, XmlSchemaSet schemas) + { + XmlSchema schema = new XmlSchema + { + ElementFormDefault = XmlSchemaForm.Qualified + }; + if (ns.Length > 0) + { + schema.TargetNamespace = ns; + schema.Namespaces.Add(Globals.TnsPrefix, ns); + } + + + schemas.Add(schema); + return schema; + } + + internal static void AddElementForm(XmlSchemaElement element, XmlSchema schema) + { + if (schema.ElementFormDefault != XmlSchemaForm.Qualified) + { + element.Form = XmlSchemaForm.Qualified; + } + } + + internal static void AddSchemaImport(string ns, XmlSchema schema) + { + if (SchemaHelper.NamespacesEqual(ns, schema.TargetNamespace) || SchemaHelper.NamespacesEqual(ns, Globals.SchemaNamespace) || SchemaHelper.NamespacesEqual(ns, Globals.SchemaInstanceNamespace)) + { + return; + } + + foreach (object item in schema.Includes) + { + if (item is XmlSchemaImport) + { + if (SchemaHelper.NamespacesEqual(ns, ((XmlSchemaImport)item).Namespace)) + { + return; + } + } + } + + XmlSchemaImport import = new XmlSchemaImport(); + if (ns != null && ns.Length > 0) + { + import.Namespace = ns; + } + + schema.Includes.Add(import); + } + + internal static XmlSchema GetSchemaWithGlobalElementDeclaration(XmlSchemaElement element, XmlSchemaSet schemas) + { + ICollection currentSchemas = schemas.Schemas(); + foreach (XmlSchema schema in currentSchemas) + { + foreach (XmlSchemaObject schemaObject in schema.Items) + { + XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement; + if (schemaElement == null) + { + continue; + } + + if (schemaElement == element) + { + return schema; + } + } + } + return null; + } + + internal static XmlQualifiedName GetGlobalElementDeclaration(XmlSchemaSet schemas, XmlQualifiedName typeQName, out bool isNullable) + { + ICollection currentSchemas = schemas.Schemas(); + string ns = typeQName.Namespace; + if (ns == null) + { + ns = string.Empty; + } + + isNullable = false; + foreach (XmlSchema schema in currentSchemas) + { + foreach (XmlSchemaObject schemaObject in schema.Items) + { + XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement; + if (schemaElement == null) + { + continue; + } + + if (schemaElement.SchemaTypeName.Equals(typeQName)) + { + isNullable = schemaElement.IsNillable; + return new XmlQualifiedName(schemaElement.Name, schema.TargetNamespace); + } + } + } + return null; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaImporter.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaImporter.cs new file mode 100644 index 0000000..b366ef2 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SchemaImporter.cs @@ -0,0 +1,1777 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using System.Xml; +using System.Xml.Schema; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + using SchemaObjectDictionary = Dictionary; + + internal class SchemaImporter + { + private readonly DataContractSet dataContractSet; + private readonly XmlSchemaSet schemaSet; + private readonly ICollection typeNames; + private readonly ICollection elements; + private readonly XmlQualifiedName[] elementTypeNames; + private readonly bool importXmlDataType; + private SchemaObjectDictionary schemaObjects; + private List redefineList; + private bool needToImportKnownTypesForObject; + private static Hashtable serializationSchemaElements; + + internal SchemaImporter(XmlSchemaSet schemas, ICollection typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames, DataContractSet dataContractSet, bool importXmlDataType) + { + this.dataContractSet = dataContractSet; + schemaSet = schemas; + this.typeNames = typeNames; + this.elements = elements; + this.elementTypeNames = elementTypeNames; + this.importXmlDataType = importXmlDataType; + } + + internal void Import() + { + if (!schemaSet.Contains(Globals.SerializationNamespace)) + { + StringReader reader = new StringReader(Globals.SerializationSchema); + XmlSchema schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); + if (schema == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace))); + } + + schemaSet.Add(schema); + } + + try + { + CompileSchemaSet(schemaSet); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.CannotImportInvalidSchemas, ex)); + } + + if (typeNames == null) + { + ICollection schemaList = schemaSet.Schemas(); + foreach (object schemaObj in schemaList) + { + if (schemaObj == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.CannotImportNullSchema)); + } + + XmlSchema schema = (XmlSchema)schemaObj; + if (schema.TargetNamespace != Globals.SerializationNamespace + && schema.TargetNamespace != Globals.SchemaNamespace) + { + foreach (XmlSchemaObject typeObj in schema.SchemaTypes.Values) + { + ImportType((XmlSchemaType)typeObj); + } + foreach (XmlSchemaElement element in schema.Elements.Values) + { + if (element.SchemaType != null) + { + ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace); + } + } + } + } + } + else + { + foreach (XmlQualifiedName typeName in typeNames) + { + if (typeName == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.CannotImportNullDataContractName)); + } + + ImportType(typeName); + } + + if (elements != null) + { + int i = 0; + foreach (XmlSchemaElement element in elements) + { + XmlQualifiedName typeName = element.SchemaTypeName; + if (typeName != null && typeName.Name.Length > 0) + { + elementTypeNames[i++] = ImportType(typeName).StableName; + } + else + { + XmlSchema schema = SchemaHelper.GetSchemaWithGlobalElementDeclaration(element, schemaSet); + if (schema == null) + { + elementTypeNames[i++] = ImportAnonymousElement(element, element.QualifiedName).StableName; + } + else + { + elementTypeNames[i++] = ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace).StableName; + } + } + } + } + } + ImportKnownTypesForObject(); + } + + internal static void CompileSchemaSet(XmlSchemaSet schemaSet) + { + if (schemaSet.Contains(XmlSchema.Namespace)) + { + schemaSet.Compile(); + } + else + { + // Add base XSD schema with top level element named "schema" + XmlSchema xsdSchema = new XmlSchema + { + TargetNamespace = XmlSchema.Namespace + }; + XmlSchemaElement element = new XmlSchemaElement + { + Name = Globals.SchemaLocalName, + SchemaType = new XmlSchemaComplexType() + }; + xsdSchema.Items.Add(element); + schemaSet.Add(xsdSchema); + schemaSet.Compile(); + } + } + + private SchemaObjectDictionary SchemaObjects + { + get + { + if (schemaObjects == null) + { + schemaObjects = CreateSchemaObjects(); + } + + return schemaObjects; + } + } + + private List RedefineList + { + get + { + if (redefineList == null) + { + redefineList = CreateRedefineList(); + } + + return redefineList; + } + } + + private void ImportKnownTypes(XmlQualifiedName typeName) + { + if (SchemaObjects.TryGetValue(typeName, out SchemaObjectInfo schemaObjectInfo)) + { + List knownTypes = schemaObjectInfo.knownTypes; + if (knownTypes != null) + { + foreach (XmlSchemaType knownType in knownTypes) + { + ImportType(knownType); + } + } + } + } + + internal static bool IsObjectContract(DataContract dataContract) + { + Dictionary previousCollectionTypes = new Dictionary(); + while (dataContract is CollectionDataContract) + { + if (dataContract.OriginalUnderlyingType == null) + { + dataContract = ((CollectionDataContract)dataContract).ItemContract; + continue; + } + + if (!previousCollectionTypes.ContainsKey(dataContract.OriginalUnderlyingType)) + { + previousCollectionTypes.Add(dataContract.OriginalUnderlyingType, dataContract.OriginalUnderlyingType); + dataContract = ((CollectionDataContract)dataContract).ItemContract; + } + else + { + break; + } + } + + return dataContract is PrimitiveDataContract && ((PrimitiveDataContract)dataContract).UnderlyingType == Globals.TypeOfObject; + } + + private void ImportKnownTypesForObject() + { + if (!needToImportKnownTypesForObject) + { + return; + } + + needToImportKnownTypesForObject = false; + if (dataContractSet.KnownTypesForObject == null) + { + if (SchemaObjects.TryGetValue(SchemaExporter.AnytypeQualifiedName, out SchemaObjectInfo schemaObjectInfo)) + { + List knownTypes = schemaObjectInfo.knownTypes; + if (knownTypes != null) + { + DataContractDictionary knownDataContracts = new DataContractDictionary(); + foreach (XmlSchemaType knownType in knownTypes) + { + // Expected: will throw exception if schema set contains types that are not supported + DataContract dataContract = ImportType(knownType); + if (!knownDataContracts.TryGetValue(dataContract.StableName, out DataContract existingContract)) + { + knownDataContracts.Add(dataContract.StableName, dataContract); + } + } + dataContractSet.KnownTypesForObject = knownDataContracts; + } + } + } + } + + internal SchemaObjectDictionary CreateSchemaObjects() + { + SchemaObjectDictionary schemaObjects = new SchemaObjectDictionary(); + ICollection schemaList = schemaSet.Schemas(); + List knownTypesForObject = new List(); + schemaObjects.Add(SchemaExporter.AnytypeQualifiedName, new SchemaObjectInfo(null, null, null, knownTypesForObject)); + + foreach (XmlSchema schema in schemaList) + { + if (schema.TargetNamespace != Globals.SerializationNamespace) + { + foreach (XmlSchemaObject schemaObj in schema.SchemaTypes.Values) + { + XmlSchemaType schemaType = schemaObj as XmlSchemaType; + if (schemaType != null) + { + knownTypesForObject.Add(schemaType); + + XmlQualifiedName currentTypeName = new XmlQualifiedName(schemaType.Name, schema.TargetNamespace); + if (schemaObjects.TryGetValue(currentTypeName, out SchemaObjectInfo schemaObjectInfo)) + { + schemaObjectInfo.type = schemaType; + schemaObjectInfo.schema = schema; + } + else + { + schemaObjects.Add(currentTypeName, new SchemaObjectInfo(schemaType, null, schema, null)); + } + + XmlQualifiedName baseTypeName = GetBaseTypeName(schemaType); + if (baseTypeName != null) + { + if (schemaObjects.TryGetValue(baseTypeName, out SchemaObjectInfo baseTypeInfo)) + { + if (baseTypeInfo.knownTypes == null) + { + baseTypeInfo.knownTypes = new List(); + } + } + else + { + baseTypeInfo = new SchemaObjectInfo(null, null, null, new List()); + schemaObjects.Add(baseTypeName, baseTypeInfo); + } + baseTypeInfo.knownTypes.Add(schemaType); + } + } + } + foreach (XmlSchemaObject schemaObj in schema.Elements.Values) + { + XmlSchemaElement schemaElement = schemaObj as XmlSchemaElement; + if (schemaElement != null) + { + XmlQualifiedName currentElementName = new XmlQualifiedName(schemaElement.Name, schema.TargetNamespace); + if (schemaObjects.TryGetValue(currentElementName, out SchemaObjectInfo schemaObjectInfo)) + { + schemaObjectInfo.element = schemaElement; + schemaObjectInfo.schema = schema; + } + else + { + schemaObjects.Add(currentElementName, new SchemaObjectInfo(null, schemaElement, schema, null)); + } + } + } + } + } + return schemaObjects; + } + + private XmlQualifiedName GetBaseTypeName(XmlSchemaType type) + { + XmlQualifiedName baseTypeName = null; + XmlSchemaComplexType complexType = type as XmlSchemaComplexType; + if (complexType != null) + { + if (complexType.ContentModel != null) + { + XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent; + if (complexContent != null) + { + XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension; + if (extension != null) + { + baseTypeName = extension.BaseTypeName; + } + } + } + } + return baseTypeName; + } + + private List CreateRedefineList() + { + List list = new List(); + + ICollection schemaList = schemaSet.Schemas(); + foreach (object schemaObj in schemaList) + { + XmlSchema schema = schemaObj as XmlSchema; + if (schema == null) + { + continue; + } + + foreach (XmlSchemaExternal ext in schema.Includes) + { + XmlSchemaRedefine redefine = ext as XmlSchemaRedefine; + if (redefine != null) + { + list.Add(redefine); + } + } + } + + return list; + } + + private DataContract ImportAnonymousGlobalElement(XmlSchemaElement element, XmlQualifiedName typeQName, string ns) + { + DataContract contract = ImportAnonymousElement(element, typeQName); + XmlDataContract xmlDataContract = contract as XmlDataContract; + if (xmlDataContract != null) + { + xmlDataContract.SetTopLevelElementName(new XmlQualifiedName(element.Name, ns)); + xmlDataContract.IsTopLevelElementNullable = element.IsNillable; + } + return contract; + } + + private DataContract ImportAnonymousElement(XmlSchemaElement element, XmlQualifiedName typeQName) + { + if (SchemaHelper.GetSchemaType(SchemaObjects, typeQName) != null) + { + for (int i = 1; ; i++) + { + typeQName = new XmlQualifiedName(typeQName.Name + i.ToString(NumberFormatInfo.InvariantInfo), typeQName.Namespace); + if (SchemaHelper.GetSchemaType(SchemaObjects, typeQName) == null) + { + break; + } + + if (i == int.MaxValue) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CannotComputeUniqueName, element.Name))); + } + } + } + if (element.SchemaType == null) + { + return ImportType(SchemaExporter.AnytypeQualifiedName); + } + else + { + return ImportType(element.SchemaType, typeQName, true/*isAnonymous*/); + } + } + + private DataContract ImportType(XmlQualifiedName typeName) + { + DataContract dataContract = DataContract.GetBuiltInDataContract(typeName.Name, typeName.Namespace); + if (dataContract == null) + { + XmlSchemaType type = SchemaHelper.GetSchemaType(SchemaObjects, typeName); + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SpecifiedTypeNotFoundInSchema, typeName.Name, typeName.Namespace))); + } + + dataContract = ImportType(type); + } + if (IsObjectContract(dataContract)) + { + needToImportKnownTypesForObject = true; + } + + return dataContract; + } + + private DataContract ImportType(XmlSchemaType type) + { + return ImportType(type, type.QualifiedName, false/*isAnonymous*/); + } + + private DataContract ImportType(XmlSchemaType type, XmlQualifiedName typeName, bool isAnonymous) + { + DataContract dataContract = dataContractSet[typeName]; + if (dataContract != null) + { + return dataContract; + } + + InvalidDataContractException invalidContractException; + try + { + foreach (XmlSchemaRedefine redefine in RedefineList) + { + if (redefine.SchemaTypes[typeName] != null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.RedefineNotSupported); + } + } + + if (type is XmlSchemaSimpleType simpleType) + { + XmlSchemaSimpleTypeContent content = simpleType.Content; + if (content is XmlSchemaSimpleTypeUnion) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.SimpleTypeUnionNotSupported); + } + else if (content is XmlSchemaSimpleTypeList) + { + dataContract = ImportFlagsEnum(typeName, (XmlSchemaSimpleTypeList)content, simpleType.Annotation); + } + else if (content is XmlSchemaSimpleTypeRestriction) + { + XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)content; + if (CheckIfEnum(restriction)) + { + dataContract = ImportEnum(typeName, restriction, false /*isFlags*/, simpleType.Annotation); + } + else + { + dataContract = ImportSimpleTypeRestriction(typeName, restriction); + if (dataContract.IsBuiltInDataContract && !isAnonymous) + { + dataContractSet.InternalAdd(typeName, dataContract); + } + } + } + } + else if (type is XmlSchemaComplexType complexType) + { + if (complexType.ContentModel == null) + { + CheckComplexType(typeName, complexType); + dataContract = ImportType(typeName, complexType.Particle, complexType.Attributes, complexType.AnyAttribute, null /* baseTypeName */, complexType.Annotation); + } + else + { + XmlSchemaContentModel contentModel = complexType.ContentModel; + if (contentModel is XmlSchemaSimpleContent) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.SimpleContentNotSupported); + } + else if (contentModel is XmlSchemaComplexContent complexContent) + { + if (complexContent.IsMixed) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.MixedContentNotSupported); + } + + if (complexContent.Content is XmlSchemaComplexContentExtension extension) + { + dataContract = ImportType(typeName, extension.Particle, extension.Attributes, extension.AnyAttribute, extension.BaseTypeName, complexType.Annotation); + } + else if (complexContent.Content is XmlSchemaComplexContentRestriction restriction) + { + XmlQualifiedName baseTypeName = restriction.BaseTypeName; + if (baseTypeName == SchemaExporter.AnytypeQualifiedName) + { + dataContract = ImportType(typeName, restriction.Particle, restriction.Attributes, restriction.AnyAttribute, null /* baseTypeName */, complexType.Annotation); + } + else + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.ComplexTypeRestrictionNotSupported); + } + } + } + } + } + + if (dataContract == null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, string.Empty); + } + + if (type.QualifiedName != XmlQualifiedName.Empty) + { + ImportTopLevelElement(typeName); + } + + ImportDataContractExtension(type, dataContract); + ImportGenericInfo(type, dataContract); + ImportKnownTypes(typeName); + + return dataContract; + } + catch (InvalidDataContractException e) + { + invalidContractException = e; + } + + // Execution gets to this point if InvalidDataContractException was thrown + if (importXmlDataType) + { + RemoveFailedContract(typeName); + return ImportXmlDataType(typeName, type, isAnonymous); + } + if (dataContractSet.TryGetReferencedType(typeName, dataContract, out Type referencedType) + || (string.IsNullOrEmpty(type.Name) && dataContractSet.TryGetReferencedType(ImportActualType(type.Annotation, typeName, typeName), dataContract, out referencedType))) + { + if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) + { + RemoveFailedContract(typeName); + return ImportXmlDataType(typeName, type, isAnonymous); + } + } + XmlDataContract specialContract = ImportSpecialXmlDataType(type, isAnonymous); + if (specialContract != null) + { + dataContractSet.Remove(typeName); + return specialContract; + } + + throw invalidContractException; + } + + private void RemoveFailedContract(XmlQualifiedName typeName) + { + ClassDataContract oldContract = dataContractSet[typeName] as ClassDataContract; + dataContractSet.Remove(typeName); + if (oldContract != null) + { + ClassDataContract ancestorDataContract = oldContract.BaseContract; + while (ancestorDataContract != null) + { + ancestorDataContract.KnownDataContracts.Remove(typeName); + ancestorDataContract = ancestorDataContract.BaseContract; + } + if (dataContractSet.KnownTypesForObject != null) + { + dataContractSet.KnownTypesForObject.Remove(typeName); + } + } + } + + private bool CheckIfEnum(XmlSchemaSimpleTypeRestriction restriction) + { + foreach (XmlSchemaFacet facet in restriction.Facets) + { + if (!(facet is XmlSchemaEnumerationFacet)) + { + return false; + } + } + + XmlQualifiedName expectedBase = SchemaExporter.StringQualifiedName; + if (restriction.BaseTypeName != XmlQualifiedName.Empty) + { + return ((restriction.BaseTypeName == expectedBase && restriction.Facets.Count > 0) || ImportType(restriction.BaseTypeName) is EnumDataContract); + } + else if (restriction.BaseType != null) + { + DataContract baseContract = ImportType(restriction.BaseType); + return (baseContract.StableName == expectedBase || baseContract is EnumDataContract); + } + + return false; + } + + private bool CheckIfCollection(XmlSchemaSequence rootSequence) + { + if (rootSequence.Items == null || rootSequence.Items.Count == 0) + { + return false; + } + + RemoveOptionalUnknownSerializationElements(rootSequence.Items); + if (rootSequence.Items.Count != 1) + { + return false; + } + + XmlSchemaObject o = rootSequence.Items[0]; + if (!(o is XmlSchemaElement)) + { + return false; + } + + XmlSchemaElement localElement = (XmlSchemaElement)o; + return (localElement.MaxOccursString == Globals.OccursUnbounded || localElement.MaxOccurs > 1); + } + + private bool CheckIfISerializable(XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes) + { + if (rootSequence.Items == null || rootSequence.Items.Count == 0) + { + return false; + } + + RemoveOptionalUnknownSerializationElements(rootSequence.Items); + + if (attributes == null || attributes.Count == 0) + { + return false; + } + + return (rootSequence.Items.Count == 1 && rootSequence.Items[0] is XmlSchemaAny); + } + + private void RemoveOptionalUnknownSerializationElements(XmlSchemaObjectCollection items) + { + for (int i = 0; i < items.Count; i++) + { + XmlSchemaElement element = items[i] as XmlSchemaElement; + if (element != null && element.RefName != null && + element.RefName.Namespace == Globals.SerializationNamespace && + element.MinOccurs == 0) + { + if (serializationSchemaElements == null) + { + XmlSchema serializationSchema = XmlSchema.Read(XmlReader.Create(new StringReader(Globals.SerializationSchema)), null); + serializationSchemaElements = new Hashtable(); + foreach (XmlSchemaObject schemaObject in serializationSchema.Items) + { + XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement; + if (schemaElement != null) + { + serializationSchemaElements.Add(schemaElement.Name, schemaElement); + } + } + } + if (!serializationSchemaElements.ContainsKey(element.RefName.Name)) + { + items.RemoveAt(i); + i--; + } + } + } + } + + private DataContract ImportType(XmlQualifiedName typeName, XmlSchemaParticle rootParticle, XmlSchemaObjectCollection attributes, XmlSchemaAnyAttribute anyAttribute, XmlQualifiedName baseTypeName, XmlSchemaAnnotation annotation) + { + DataContract dataContract = null; + bool isDerived = (baseTypeName != null); + + ImportAttributes(typeName, attributes, anyAttribute, out bool isReference); + + if (rootParticle == null) + { + dataContract = ImportClass(typeName, new XmlSchemaSequence(), baseTypeName, annotation, isReference); + } + else if (!(rootParticle is XmlSchemaSequence)) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.RootParticleMustBeSequence); + } + else + { + XmlSchemaSequence rootSequence = (XmlSchemaSequence)rootParticle; + if (rootSequence.MinOccurs != 1) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.RootSequenceMustBeRequired); + } + + if (rootSequence.MaxOccurs != 1) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.RootSequenceMaxOccursMustBe); + } + + if (!isDerived && CheckIfCollection(rootSequence)) + { + dataContract = ImportCollection(typeName, rootSequence, attributes, annotation, isReference); + } + else if (CheckIfISerializable(rootSequence, attributes)) + { + dataContract = ImportISerializable(typeName, rootSequence, baseTypeName, attributes, annotation); + } + else + { + dataContract = ImportClass(typeName, rootSequence, baseTypeName, annotation, isReference); + } + } + return dataContract; + } + + private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName baseTypeName, XmlSchemaAnnotation annotation, bool isReference) + { + ClassDataContract dataContract = new ClassDataContract + { + StableName = typeName + }; + AddDataContract(dataContract); + + dataContract.IsValueType = IsValueType(typeName, annotation); + dataContract.IsReference = isReference; + if (baseTypeName != null) + { + ImportBaseContract(baseTypeName, dataContract); + if (dataContract.BaseContract.IsISerializable) + { + if (IsISerializableDerived(typeName, rootSequence)) + { + dataContract.IsISerializable = true; + } + else + { + ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.DerivedTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); + } + } + if (dataContract.BaseContract.IsReference) + { + dataContract.IsReference = true; + } + } + + if (!dataContract.IsISerializable) + { + dataContract.Members = new List(); + RemoveOptionalUnknownSerializationElements(rootSequence.Items); + for (int memberIndex = 0; memberIndex < rootSequence.Items.Count; memberIndex++) + { + XmlSchemaElement element = rootSequence.Items[memberIndex] as XmlSchemaElement; + if (element == null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.MustContainOnlyLocalElements); + } + + ImportClassMember(element, dataContract); + } + } + + return dataContract; + } + + private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType xsdType, bool isAnonymous) + { + DataContract dataContract = dataContractSet[typeName]; + if (dataContract != null) + { + return dataContract; + } + + XmlDataContract xmlDataContract = ImportSpecialXmlDataType(xsdType, isAnonymous); + if (xmlDataContract != null) + { + return xmlDataContract; + } + + xmlDataContract = new XmlDataContract + { + StableName = typeName, + IsValueType = false + }; + AddDataContract(xmlDataContract); + if (xsdType != null) + { + ImportDataContractExtension(xsdType, xmlDataContract); + xmlDataContract.IsValueType = IsValueType(typeName, xsdType.Annotation); + xmlDataContract.IsTypeDefinedOnImport = true; + xmlDataContract.XsdType = isAnonymous ? xsdType : null; + xmlDataContract.HasRoot = !IsXmlAnyElementType(xsdType as XmlSchemaComplexType); + } + else + { + //Value type can be used by both nillable and non-nillable elements but reference type cannot be used by non nillable elements + xmlDataContract.IsValueType = true; + xmlDataContract.IsTypeDefinedOnImport = false; + xmlDataContract.HasRoot = true; + } + if (!isAnonymous) + { + xmlDataContract.SetTopLevelElementName(SchemaHelper.GetGlobalElementDeclaration(schemaSet, typeName, out bool isNullable)); + xmlDataContract.IsTopLevelElementNullable = isNullable; + } + return xmlDataContract; + } + + private XmlDataContract ImportSpecialXmlDataType(XmlSchemaType xsdType, bool isAnonymous) + { + if (!isAnonymous) + { + return null; + } + + XmlSchemaComplexType complexType = xsdType as XmlSchemaComplexType; + if (complexType == null) + { + return null; + } + + if (IsXmlAnyElementType(complexType)) + { + //check if the type is XElement + XmlQualifiedName xlinqTypeName = new XmlQualifiedName("XElement", "http://schemas.datacontract.org/2004/07/System.Xml.Linq"); + if (dataContractSet.TryGetReferencedType(xlinqTypeName, null, out Type referencedType) + && Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) + { + XmlDataContract xmlDataContract = new XmlDataContract(referencedType); + AddDataContract(xmlDataContract); + return xmlDataContract; + } + //otherwise, assume XmlElement + return (XmlDataContract)DataContract.GetBuiltInDataContract(Globals.TypeOfXmlElement); + } + if (IsXmlAnyType(complexType)) + { + return (XmlDataContract)DataContract.GetBuiltInDataContract(Globals.TypeOfXmlNodeArray); + } + + return null; + } + + private bool IsXmlAnyElementType(XmlSchemaComplexType xsdType) + { + if (xsdType == null) + { + return false; + } + + XmlSchemaSequence sequence = xsdType.Particle as XmlSchemaSequence; + if (sequence == null) + { + return false; + } + + if (sequence.Items == null || sequence.Items.Count != 1) + { + return false; + } + + XmlSchemaAny any = sequence.Items[0] as XmlSchemaAny; + if (any == null || any.Namespace != null) + { + return false; + } + + if (xsdType.AnyAttribute != null || (xsdType.Attributes != null && xsdType.Attributes.Count > 0)) + { + return false; + } + + return true; + } + + private bool IsXmlAnyType(XmlSchemaComplexType xsdType) + { + if (xsdType == null) + { + return false; + } + + XmlSchemaSequence sequence = xsdType.Particle as XmlSchemaSequence; + if (sequence == null) + { + return false; + } + + if (sequence.Items == null || sequence.Items.Count != 1) + { + return false; + } + + XmlSchemaAny any = sequence.Items[0] as XmlSchemaAny; + if (any == null || any.Namespace != null) + { + return false; + } + + if (any.MaxOccurs != decimal.MaxValue) + { + return false; + } + + if (xsdType.AnyAttribute == null || xsdType.Attributes.Count > 0) + { + return false; + } + + return true; + } + + private bool IsValueType(XmlQualifiedName typeName, XmlSchemaAnnotation annotation) + { + string isValueTypeInnerText = GetInnerText(typeName, ImportAnnotation(annotation, SchemaExporter.IsValueTypeName)); + if (isValueTypeInnerText != null) + { + try + { + return XmlConvert.ToBoolean(isValueTypeInnerText); + } + catch (FormatException fe) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.IsValueTypeFormattedIncorrectly, isValueTypeInnerText, fe.Message)); + } + } + return false; + } + + private ClassDataContract ImportISerializable(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName baseTypeName, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation annotation) + { + ClassDataContract dataContract = new ClassDataContract + { + StableName = typeName, + IsISerializable = true + }; + AddDataContract(dataContract); + + dataContract.IsValueType = IsValueType(typeName, annotation); + if (baseTypeName == null) + { + CheckISerializableBase(typeName, rootSequence, attributes); + } + else + { + ImportBaseContract(baseTypeName, dataContract); + if (!dataContract.BaseContract.IsISerializable) + { + ThrowISerializableTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.BaseTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); + } + + if (!IsISerializableDerived(typeName, rootSequence)) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.ISerializableDerivedContainsOneOrMoreItems); + } + } + + return dataContract; + } + + private void CheckISerializableBase(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes) + { + if (rootSequence == null) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.ISerializableDoesNotContainAny); + } + + if (rootSequence.Items == null || rootSequence.Items.Count < 1) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.ISerializableDoesNotContainAny); + } + else if (rootSequence.Items.Count > 1) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.ISerializableContainsMoreThanOneItems); + } + + XmlSchemaObject o = rootSequence.Items[0]; + if (!(o is XmlSchemaAny)) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.ISerializableDoesNotContainAny); + } + + XmlSchemaAny wildcard = (XmlSchemaAny)o; + XmlSchemaAny iSerializableWildcardElement = SchemaExporter.ISerializableWildcardElement; + if (wildcard.MinOccurs != iSerializableWildcardElement.MinOccurs) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardMinOccursMustBe, iSerializableWildcardElement.MinOccurs)); + } + + if (wildcard.MaxOccursString != iSerializableWildcardElement.MaxOccursString) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardMaxOccursMustBe, iSerializableWildcardElement.MaxOccursString)); + } + + if (wildcard.Namespace != iSerializableWildcardElement.Namespace) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardNamespaceInvalid, iSerializableWildcardElement.Namespace)); + } + + if (wildcard.ProcessContents != iSerializableWildcardElement.ProcessContents) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardProcessContentsInvalid, iSerializableWildcardElement.ProcessContents)); + } + + XmlQualifiedName factoryTypeAttributeRefName = SchemaExporter.ISerializableFactoryTypeAttribute.RefName; + bool containsFactoryTypeAttribute = false; + if (attributes != null) + { + for (int i = 0; i < attributes.Count; i++) + { + o = attributes[i]; + if (o is XmlSchemaAttribute) + { + if (((XmlSchemaAttribute)o).RefName == factoryTypeAttributeRefName) + { + containsFactoryTypeAttribute = true; + break; + } + } + } + } + if (!containsFactoryTypeAttribute) + { + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableMustRefFactoryTypeAttribute, factoryTypeAttributeRefName.Name, factoryTypeAttributeRefName.Namespace)); + } + } + + private bool IsISerializableDerived(XmlQualifiedName typeName, XmlSchemaSequence rootSequence) + { + return (rootSequence == null || rootSequence.Items == null || rootSequence.Items.Count == 0); + } + + private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract dataContract) + { + ClassDataContract baseContract = ImportType(baseTypeName) as ClassDataContract; + if (baseContract == null) + { + ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(dataContract.IsISerializable ? SR.InvalidISerializableDerivation : SR.InvalidClassDerivation, baseTypeName.Name, baseTypeName.Namespace)); + } + + // Note: code ignores IsValueType annotation if derived type exists + if (baseContract.IsValueType) + { + baseContract.IsValueType = false; + } + + ClassDataContract ancestorDataContract = baseContract; + while (ancestorDataContract != null) + { + DataContractDictionary knownDataContracts = ancestorDataContract.KnownDataContracts; + if (knownDataContracts == null) + { + knownDataContracts = new DataContractDictionary(); + ancestorDataContract.KnownDataContracts = knownDataContracts; + } + knownDataContracts.Add(dataContract.StableName, dataContract); + ancestorDataContract = ancestorDataContract.BaseContract; + } + + dataContract.BaseContract = baseContract; + } + + private void ImportTopLevelElement(XmlQualifiedName typeName) + { + XmlSchemaElement topLevelElement = SchemaHelper.GetSchemaElement(SchemaObjects, typeName); + // Top level element of same name is not required, but is validated if it is present + if (topLevelElement == null) + { + return; + } + else + { + XmlQualifiedName elementTypeName = topLevelElement.SchemaTypeName; + if (elementTypeName.IsEmpty) + { + if (topLevelElement.SchemaType != null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.AnonymousTypeNotSupported, typeName.Name, typeName.Namespace)); + } + else + { + elementTypeName = SchemaExporter.AnytypeQualifiedName; + } + } + if (elementTypeName != typeName) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.TopLevelElementRepresentsDifferentType, topLevelElement.SchemaTypeName.Name, topLevelElement.SchemaTypeName.Namespace)); + } + + CheckIfElementUsesUnsupportedConstructs(typeName, topLevelElement); + } + } + + private void ImportClassMember(XmlSchemaElement element, ClassDataContract dataContract) + { + XmlQualifiedName typeName = dataContract.StableName; + + if (element.MinOccurs > 1) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementMinOccursMustBe, element.Name)); + } + + if (element.MaxOccurs != 1) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementMaxOccursMustBe, element.Name)); + } + + DataContract memberTypeContract = null; + string memberName = element.Name; + bool memberIsRequired = (element.MinOccurs > 0); + bool memberIsNullable = element.IsNillable; + bool memberEmitDefaultValue; + int memberOrder = 0; + + XmlSchemaForm elementForm = (element.Form == XmlSchemaForm.None) ? SchemaHelper.GetSchemaWithType(SchemaObjects, schemaSet, typeName).ElementFormDefault : element.Form; + if (elementForm != XmlSchemaForm.Qualified) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.FormMustBeQualified, element.Name)); + } + + CheckIfElementUsesUnsupportedConstructs(typeName, element); + + if (element.SchemaTypeName.IsEmpty) + { + if (element.SchemaType != null) + { + memberTypeContract = ImportAnonymousElement(element, new XmlQualifiedName(string.Format(CultureInfo.InvariantCulture, "{0}.{1}Type", typeName.Name, element.Name), typeName.Namespace)); + } + else if (!element.RefName.IsEmpty) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementRefOnLocalElementNotSupported, element.RefName.Name, element.RefName.Namespace)); + } + else + { + memberTypeContract = ImportType(SchemaExporter.AnytypeQualifiedName); + } + } + else + { + XmlQualifiedName memberTypeName = ImportActualType(element.Annotation, element.SchemaTypeName, typeName); + memberTypeContract = ImportType(memberTypeName); + if (IsObjectContract(memberTypeContract)) + { + needToImportKnownTypesForObject = true; + } + } + bool? emitDefaultValueFromAnnotation = ImportEmitDefaultValue(element.Annotation, typeName); + if (!memberTypeContract.IsValueType && !memberIsNullable) + { + if (emitDefaultValueFromAnnotation != null && emitDefaultValueFromAnnotation.Value) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidEmitDefaultAnnotation, memberName, typeName.Name, typeName.Namespace))); + } + + memberEmitDefaultValue = false; + } + else + { + memberEmitDefaultValue = emitDefaultValueFromAnnotation != null ? emitDefaultValueFromAnnotation.Value : Globals.DefaultEmitDefaultValue; + } + + int prevMemberIndex = dataContract.Members.Count - 1; + if (prevMemberIndex >= 0) + { + DataMember prevMember = dataContract.Members[prevMemberIndex]; + if (prevMember.Order > Globals.DefaultOrder) + { + memberOrder = dataContract.Members.Count; + } + + DataMember currentMember = new DataMember(memberTypeContract, memberName, memberIsNullable, memberIsRequired, memberEmitDefaultValue, memberOrder); + int compare = ClassDataContract.DataMemberComparer.Singleton.Compare(prevMember, currentMember); + if (compare == 0) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.CannotHaveDuplicateElementNames, memberName)); + } + else if (compare > 0) + { + memberOrder = dataContract.Members.Count; + } + } + DataMember dataMember = new DataMember(memberTypeContract, memberName, memberIsNullable, memberIsRequired, memberEmitDefaultValue, memberOrder); + + XmlQualifiedName surrogateDataAnnotationName = SchemaExporter.SurrogateDataAnnotationName; + dataContractSet.SetSurrogateData(dataMember, ImportSurrogateData(ImportAnnotation(element.Annotation, surrogateDataAnnotationName), surrogateDataAnnotationName.Name, surrogateDataAnnotationName.Namespace)); + + dataContract.Members.Add(dataMember); + } + + private bool? ImportEmitDefaultValue(XmlSchemaAnnotation annotation, XmlQualifiedName typeName) + { + XmlElement defaultValueElement = ImportAnnotation(annotation, SchemaExporter.DefaultValueAnnotation); + if (defaultValueElement == null) + { + return null; + } + + XmlNode emitDefaultValueAttribute = defaultValueElement.Attributes.GetNamedItem(Globals.EmitDefaultValueAttribute); + string emitDefaultValueString = (emitDefaultValueAttribute == null) ? null : emitDefaultValueAttribute.Value; + if (emitDefaultValueString == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, SchemaExporter.DefaultValueAnnotation.Name, typeName.Name, typeName.Namespace, Globals.EmitDefaultValueAttribute))); + } + + return XmlConvert.ToBoolean(emitDefaultValueString); + } + + internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation annotation, XmlQualifiedName defaultTypeName, XmlQualifiedName typeName) + { + XmlElement actualTypeElement = ImportAnnotation(annotation, SchemaExporter.ActualTypeAnnotationName); + if (actualTypeElement == null) + { + return defaultTypeName; + } + + XmlNode nameAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNameAttribute); + string name = (nameAttribute == null) ? null : nameAttribute.Value; + if (name == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, SchemaExporter.ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNameAttribute))); + } + + XmlNode nsAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNamespaceAttribute); + string ns = (nsAttribute == null) ? null : nsAttribute.Value; + if (ns == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, SchemaExporter.ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNamespaceAttribute))); + } + + return new XmlQualifiedName(name, ns); + } + + private CollectionDataContract ImportCollection(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation annotation, bool isReference) + { + CollectionDataContract dataContract = new CollectionDataContract(CollectionKind.Array) + { + StableName = typeName + }; + AddDataContract(dataContract); + + dataContract.IsReference = isReference; + + // CheckIfCollection has already checked if sequence contains exactly one item with maxOccurs="unbounded" or maxOccurs > 1 + XmlSchemaElement element = (XmlSchemaElement)rootSequence.Items[0]; + + dataContract.IsItemTypeNullable = element.IsNillable; + dataContract.ItemName = element.Name; + + XmlSchemaForm elementForm = (element.Form == XmlSchemaForm.None) ? SchemaHelper.GetSchemaWithType(SchemaObjects, schemaSet, typeName).ElementFormDefault : element.Form; + if (elementForm != XmlSchemaForm.Qualified) + { + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ArrayItemFormMustBe, element.Name)); + } + + CheckIfElementUsesUnsupportedConstructs(typeName, element); + + if (element.SchemaTypeName.IsEmpty) + { + if (element.SchemaType != null) + { + XmlQualifiedName shortName = new XmlQualifiedName(element.Name, typeName.Namespace); + DataContract contract = dataContractSet[shortName]; + if (contract == null) + { + dataContract.ItemContract = ImportAnonymousElement(element, shortName); + } + else + { + XmlQualifiedName fullName = new XmlQualifiedName(string.Format(CultureInfo.InvariantCulture, "{0}.{1}Type", typeName.Name, element.Name), typeName.Namespace); + dataContract.ItemContract = ImportAnonymousElement(element, fullName); + } + } + else if (!element.RefName.IsEmpty) + { + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementRefOnLocalElementNotSupported, element.RefName.Name, element.RefName.Namespace)); + } + else + { + dataContract.ItemContract = ImportType(SchemaExporter.AnytypeQualifiedName); + } + } + else + { + dataContract.ItemContract = ImportType(element.SchemaTypeName); + } + + if (IsDictionary(typeName, annotation)) + { + ClassDataContract keyValueContract = dataContract.ItemContract as ClassDataContract; + DataMember key = null, value = null; + if (keyValueContract == null || keyValueContract.Members == null || keyValueContract.Members.Count != 2 + || !(key = keyValueContract.Members[0]).IsRequired || !(value = keyValueContract.Members[1]).IsRequired) + { + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.InvalidKeyValueType, element.Name)); + } + if (keyValueContract.Namespace != dataContract.Namespace) + { + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.InvalidKeyValueTypeNamespace, element.Name, keyValueContract.Namespace)); + } + keyValueContract.IsValueType = true; + dataContract.KeyName = key.Name; + dataContract.ValueName = value.Name; + if (element.SchemaType != null) + { + dataContractSet.Remove(keyValueContract.StableName); + + GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfKeyValue), Globals.TypeOfKeyValue.FullName); + genericInfo.Add(GetGenericInfoForDataMember(key)); + genericInfo.Add(GetGenericInfoForDataMember(value)); + genericInfo.AddToLevel(0, 2); + dataContract.ItemContract.StableName = new XmlQualifiedName(genericInfo.GetExpandedStableName().Name, typeName.Namespace); + } + } + + return dataContract; + } + + private GenericInfo GetGenericInfoForDataMember(DataMember dataMember) + { + GenericInfo genericInfo = null; + if (dataMember.MemberTypeContract.IsValueType && dataMember.IsNullable) + { + genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName); + genericInfo.Add(new GenericInfo(dataMember.MemberTypeContract.StableName, null)); + } + else + { + genericInfo = new GenericInfo(dataMember.MemberTypeContract.StableName, null); + } + + return genericInfo; + } + + private bool IsDictionary(XmlQualifiedName typeName, XmlSchemaAnnotation annotation) + { + string isDictionaryInnerText = GetInnerText(typeName, ImportAnnotation(annotation, SchemaExporter.IsDictionaryAnnotationName)); + if (isDictionaryInnerText != null) + { + try + { + return XmlConvert.ToBoolean(isDictionaryInnerText); + } + catch (FormatException fe) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.IsDictionaryFormattedIncorrectly, isDictionaryInnerText, fe.Message)); + } + } + return false; + } + + private EnumDataContract ImportFlagsEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeList list, XmlSchemaAnnotation annotation) + { + XmlSchemaSimpleType anonymousType = list.ItemType; + if (anonymousType == null) + { + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumListMustContainAnonymousType)); + } + + XmlSchemaSimpleTypeContent content = anonymousType.Content; + if (content is XmlSchemaSimpleTypeUnion) + { + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumUnionInAnonymousTypeNotSupported)); + } + else if (content is XmlSchemaSimpleTypeList) + { + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumListInAnonymousTypeNotSupported)); + } + else if (content is XmlSchemaSimpleTypeRestriction) + { + XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)content; + if (CheckIfEnum(restriction)) + { + return ImportEnum(typeName, restriction, true /*isFlags*/, annotation); + } + else + { + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.EnumRestrictionInvalid); + } + } + return null; + } + + private EnumDataContract ImportEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction, bool isFlags, XmlSchemaAnnotation annotation) + { + EnumDataContract dataContract = new EnumDataContract + { + StableName = typeName, + BaseContractName = ImportActualType(annotation, SchemaExporter.DefaultEnumBaseTypeName, typeName), + IsFlags = isFlags + }; + AddDataContract(dataContract); + + // CheckIfEnum has already checked if baseType of restriction is string + dataContract.Values = new List(); + dataContract.Members = new List(); + foreach (XmlSchemaFacet facet in restriction.Facets) + { + XmlSchemaEnumerationFacet enumFacet = facet as XmlSchemaEnumerationFacet; + if (enumFacet == null) + { + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.EnumOnlyEnumerationFacetsSupported); + } + + if (enumFacet.Value == null) + { + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.EnumEnumerationFacetsMustHaveValue); + } + + string valueInnerText = GetInnerText(typeName, ImportAnnotation(enumFacet.Annotation, SchemaExporter.EnumerationValueAnnotationName)); + if (valueInnerText == null) + { + dataContract.Values.Add(SchemaExporter.GetDefaultEnumValue(isFlags, dataContract.Members.Count)); + } + else + { + dataContract.Values.Add(dataContract.GetEnumValueFromString(valueInnerText)); + } + + DataMember dataMember = new DataMember(enumFacet.Value); + dataContract.Members.Add(dataMember); + } + return dataContract; + } + + private DataContract ImportSimpleTypeRestriction(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction) + { + DataContract dataContract = null; + + if (!restriction.BaseTypeName.IsEmpty) + { + dataContract = ImportType(restriction.BaseTypeName); + } + else if (restriction.BaseType != null) + { + dataContract = ImportType(restriction.BaseType); + } + else + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.SimpleTypeRestrictionDoesNotSpecifyBase); + } + + return dataContract; + } + + private void ImportDataContractExtension(XmlSchemaType type, DataContract dataContract) + { + if (type.Annotation == null || type.Annotation.Items == null) + { + return; + } + + foreach (XmlSchemaObject schemaObject in type.Annotation.Items) + { + XmlSchemaAppInfo appInfo = schemaObject as XmlSchemaAppInfo; + if (appInfo == null) + { + continue; + } + + if (appInfo.Markup != null) + { + foreach (XmlNode xmlNode in appInfo.Markup) + { + XmlElement typeElement = xmlNode as XmlElement; + XmlQualifiedName surrogateDataAnnotationName = SchemaExporter.SurrogateDataAnnotationName; + if (typeElement != null && typeElement.NamespaceURI == surrogateDataAnnotationName.Namespace && typeElement.LocalName == surrogateDataAnnotationName.Name) + { + object surrogateData = ImportSurrogateData(typeElement, surrogateDataAnnotationName.Name, surrogateDataAnnotationName.Namespace); + dataContractSet.SetSurrogateData(dataContract, surrogateData); + } + } + } + } + } + + private void ImportGenericInfo(XmlSchemaType type, DataContract dataContract) + { + if (type.Annotation == null || type.Annotation.Items == null) + { + return; + } + + foreach (XmlSchemaObject schemaObject in type.Annotation.Items) + { + XmlSchemaAppInfo appInfo = schemaObject as XmlSchemaAppInfo; + if (appInfo == null) + { + continue; + } + + if (appInfo.Markup != null) + { + foreach (XmlNode xmlNode in appInfo.Markup) + { + XmlElement typeElement = xmlNode as XmlElement; + if (typeElement != null && typeElement.NamespaceURI == Globals.SerializationNamespace) + { + if (typeElement.LocalName == Globals.GenericTypeLocalName) + { + dataContract.GenericInfo = ImportGenericInfo(typeElement, type); + } + } + } + } + } + } + + private GenericInfo ImportGenericInfo(XmlElement typeElement, XmlSchemaType type) + { + XmlNode nameAttribute = typeElement.Attributes.GetNamedItem(Globals.GenericNameAttribute); + string name = (nameAttribute == null) ? null : nameAttribute.Value; + if (name == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationAttributeNotFound, type.Name, Globals.GenericNameAttribute))); + } + + XmlNode nsAttribute = typeElement.Attributes.GetNamedItem(Globals.GenericNamespaceAttribute); + string ns = (nsAttribute == null) ? null : nsAttribute.Value; + if (ns == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationAttributeNotFound, type.Name, Globals.GenericNamespaceAttribute))); + } + + if (typeElement.ChildNodes.Count > 0) //Generic Type + { + name = DataContract.EncodeLocalName(name); + } + + int currentLevel = 0; + GenericInfo genInfo = new GenericInfo(new XmlQualifiedName(name, ns), type.Name); + foreach (XmlNode childNode in typeElement.ChildNodes) + { + XmlElement argumentElement = childNode as XmlElement; + if (argumentElement == null) + { + continue; + } + + if (argumentElement.LocalName != Globals.GenericParameterLocalName || + argumentElement.NamespaceURI != Globals.SerializationNamespace) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationHasInvalidElement, argumentElement.LocalName, argumentElement.NamespaceURI, type.Name))); + } + + XmlNode nestedLevelAttribute = argumentElement.Attributes.GetNamedItem(Globals.GenericParameterNestedLevelAttribute); + int argumentLevel = 0; + if (nestedLevelAttribute != null) + { + if (!int.TryParse(nestedLevelAttribute.Value, out argumentLevel)) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationHasInvalidAttributeValue, argumentElement.LocalName, argumentElement.NamespaceURI, type.Name, nestedLevelAttribute.Value, nestedLevelAttribute.LocalName, Globals.TypeOfInt.Name))); + } + } + if (argumentLevel < currentLevel) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationForNestedLevelMustBeIncreasing, argumentElement.LocalName, argumentElement.NamespaceURI, type.Name))); + } + + genInfo.Add(ImportGenericInfo(argumentElement, type)); + genInfo.AddToLevel(argumentLevel, 1); + currentLevel = argumentLevel; + } + + XmlNode typeNestedLevelsAttribute = typeElement.Attributes.GetNamedItem(Globals.GenericParameterNestedLevelAttribute); + if (typeNestedLevelsAttribute != null) + { + if (!int.TryParse(typeNestedLevelsAttribute.Value, out int nestedLevels)) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationHasInvalidAttributeValue, typeElement.LocalName, typeElement.NamespaceURI, type.Name, typeNestedLevelsAttribute.Value, typeNestedLevelsAttribute.LocalName, Globals.TypeOfInt.Name))); + } + + if ((nestedLevels - 1) > currentLevel) + { + genInfo.AddToLevel(nestedLevels - 1, 0); + } + } + return genInfo; + } + + private object ImportSurrogateData(XmlElement typeElement, string name, string ns) + { + if (dataContractSet.DataContractSurrogate != null && typeElement != null) + { + Collection knownTypes = new Collection(); + DataContractSurrogateCaller.GetKnownCustomDataTypes(dataContractSet.DataContractSurrogate, knownTypes); + DataContractSerializer serializer = new DataContractSerializer(Globals.TypeOfObject, name, ns, knownTypes, + int.MaxValue, false /*ignoreExtensionDataObject*/, true /*preserveObjectReferences*/, null /*dataContractSurrogate*/); + return serializer.ReadObject(new XmlNodeReader(typeElement)); + } + return null; + } + + private void CheckComplexType(XmlQualifiedName typeName, XmlSchemaComplexType type) + { + if (type.IsAbstract) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.AbstractTypeNotSupported); + } + + if (type.IsMixed) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.MixedContentNotSupported); + } + } + + private void CheckIfElementUsesUnsupportedConstructs(XmlQualifiedName typeName, XmlSchemaElement element) + { + if (element.IsAbstract) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.AbstractElementNotSupported, element.Name)); + } + + if (element.DefaultValue != null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.DefaultOnElementNotSupported, element.Name)); + } + + if (element.FixedValue != null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.FixedOnElementNotSupported, element.Name)); + } + + if (!element.SubstitutionGroup.IsEmpty) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.SubstitutionGroupOnElementNotSupported, element.Name)); + } + } + + private void ImportAttributes(XmlQualifiedName typeName, XmlSchemaObjectCollection attributes, XmlSchemaAnyAttribute anyAttribute, out bool isReference) + { + if (anyAttribute != null) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.AnyAttributeNotSupported); + } + + isReference = false; + if (attributes != null) + { + bool foundId = false, foundRef = false; + for (int i = 0; i < attributes.Count; i++) + { + XmlSchemaObject o = attributes[i]; + if (o is XmlSchemaAttribute) + { + XmlSchemaAttribute attribute = (XmlSchemaAttribute)o; + if (attribute.Use == XmlSchemaUse.Prohibited) + { + continue; + } + + if (TryCheckIfAttribute(typeName, attribute, Globals.IdQualifiedName, ref foundId)) + { + continue; + } + + if (TryCheckIfAttribute(typeName, attribute, Globals.RefQualifiedName, ref foundRef)) + { + continue; + } + + if (attribute.RefName.IsEmpty || attribute.RefName.Namespace != Globals.SerializationNamespace || attribute.Use == XmlSchemaUse.Required) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.TypeShouldNotContainAttributes, Globals.SerializationNamespace)); + } + } + } + isReference = (foundId && foundRef); + } + } + + private bool TryCheckIfAttribute(XmlQualifiedName typeName, XmlSchemaAttribute attribute, XmlQualifiedName refName, ref bool foundAttribute) + { + if (attribute.RefName != refName) + { + return false; + } + + if (foundAttribute) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.CannotHaveDuplicateAttributeNames, refName.Name)); + } + + foundAttribute = true; + return true; + } + + private void AddDataContract(DataContract dataContract) + { + dataContractSet.Add(dataContract.StableName, dataContract); + } + + private string GetInnerText(XmlQualifiedName typeName, XmlElement xmlElement) + { + if (xmlElement != null) + { + XmlNode child = xmlElement.FirstChild; + while (child != null) + { + if (child.NodeType == XmlNodeType.Element) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.InvalidAnnotationExpectingText, xmlElement.LocalName, xmlElement.NamespaceURI, child.LocalName, child.NamespaceURI)); + } + + child = child.NextSibling; + } + return xmlElement.InnerText; + } + return null; + } + + private static XmlElement ImportAnnotation(XmlSchemaAnnotation annotation, XmlQualifiedName annotationQualifiedName) + { + if (annotation != null && annotation.Items != null && annotation.Items.Count > 0 && annotation.Items[0] is XmlSchemaAppInfo) + { + XmlSchemaAppInfo appInfo = (XmlSchemaAppInfo)annotation.Items[0]; + XmlNode[] markup = appInfo.Markup; + if (markup != null) + { + for (int i = 0; i < markup.Length; i++) + { + XmlElement annotationElement = markup[i] as XmlElement; + if (annotationElement != null && annotationElement.LocalName == annotationQualifiedName.Name && annotationElement.NamespaceURI == annotationQualifiedName.Namespace) + { + return annotationElement; + } + } + } + } + return null; + } + + private static void ThrowTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.TypeCannotBeImported, name, ns, message)); + } + + private static void ThrowArrayTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.ArrayTypeCannotBeImported, name, ns, message)); + } + + private static void ThrowEnumTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.EnumTypeCannotBeImported, name, ns, message)); + } + + private static void ThrowISerializableTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.ISerializableTypeCannotBeImported, name, ns, message)); + } + + private static void ThrowTypeCannotBeImportedException(string message) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeCannotBeImportedHowToFix, message))); + } + } + +} + + diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/ScopedKnownTypes.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/ScopedKnownTypes.cs new file mode 100644 index 0000000..4f71041 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/ScopedKnownTypes.cs @@ -0,0 +1,46 @@ +using System; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = System.Collections.Generic.Dictionary; + + internal struct ScopedKnownTypes + { + internal DataContractDictionary[] dataContractDictionaries; + private int count; + + internal void Push(DataContractDictionary dataContractDictionary) + { + if (dataContractDictionaries == null) + { + dataContractDictionaries = new DataContractDictionary[4]; + } + else if (count == dataContractDictionaries.Length) + { + Array.Resize(ref dataContractDictionaries, dataContractDictionaries.Length * 2); + } + + dataContractDictionaries[count++] = dataContractDictionary; + } + + internal void Pop() + { + count--; + } + + internal DataContract GetDataContract(XmlQualifiedName qname) + { + for (int i = (count - 1); i >= 0; i--) + { + DataContractDictionary dataContractDictionary = dataContractDictionaries[i]; + if (dataContractDictionary.TryGetValue(qname, out DataContract dataContract)) + { + return dataContract; + } + } + return null; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationMode.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationMode.cs new file mode 100644 index 0000000..b431eff --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationMode.cs @@ -0,0 +1,8 @@ +namespace Compat.Runtime.Serialization +{ + internal enum SerializationMode + { + SharedContract, + SharedType, + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationTrace.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationTrace.cs new file mode 100644 index 0000000..3f7fef9 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SerializationTrace.cs @@ -0,0 +1,33 @@ +using System.Diagnostics; + +namespace Compat.Runtime.Serialization +{ + internal static class SerializationTrace + { + private static TraceSource _codeGen; + + internal static SourceSwitch CodeGenerationSwitch => CodeGenerationTraceSource.Switch; + + internal static void WriteInstruction(int lineNumber, string instruction) + { + CodeGenerationTraceSource.TraceInformation("{0:00000}: {1}", lineNumber, instruction); + } + + internal static void TraceInstruction(string instruction) + { + CodeGenerationTraceSource.TraceEvent(TraceEventType.Verbose, 0, instruction); + } + + private static TraceSource CodeGenerationTraceSource + { + get + { + if (_codeGen == null) + { + _codeGen = new TraceSource("E5.Runtime.Serialization.CodeGeneration"); + } + return _codeGen; + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SpecialTypeDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SpecialTypeDataContract.cs new file mode 100644 index 0000000..825e652 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SpecialTypeDataContract.cs @@ -0,0 +1,34 @@ +using System; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal sealed class SpecialTypeDataContract : DataContract + { + public SpecialTypeDataContract(Type type) + : base(new SpecialTypeDataContractCriticalHelper(type)) + { + } + + public SpecialTypeDataContract(Type type, XmlDictionaryString name, XmlDictionaryString ns) + : base(new SpecialTypeDataContractCriticalHelper(type, name, ns)) + { + } + + internal override bool IsBuiltInDataContract => true; + + private class SpecialTypeDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + internal SpecialTypeDataContractCriticalHelper(Type type) + : base(type) + { + } + + internal SpecialTypeDataContractCriticalHelper(Type type, XmlDictionaryString name, XmlDictionaryString ns) + : base(type) + { + SetDataContractName(name, ns); + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/SurrogateDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/SurrogateDataContract.cs new file mode 100644 index 0000000..65f3714 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/SurrogateDataContract.cs @@ -0,0 +1,94 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; + +namespace Compat.Runtime.Serialization +{ + internal sealed class SurrogateDataContract : DataContract + { + private readonly SurrogateDataContractCriticalHelper _helper; + + internal SurrogateDataContract(Type type, ISerializationSurrogate serializationSurrogate) + : base(new SurrogateDataContractCriticalHelper(type, serializationSurrogate)) + { + _helper = base.Helper as SurrogateDataContractCriticalHelper; + } + + internal ISerializationSurrogate SerializationSurrogate => _helper.SerializationSurrogate; + + public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + SerializationInfo serInfo = new SerializationInfo(UnderlyingType, XmlObjectSerializer.FormatterConverter, !context.UnsafeTypeForwardingEnabled); + SerializationSurrogateGetObjectData(obj, serInfo, context.GetStreamingContext()); + context.WriteSerializationInfo(xmlWriter, UnderlyingType, serInfo); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private object SerializationSurrogateSetObjectData(object obj, SerializationInfo serInfo, StreamingContext context) + { + return SerializationSurrogate.SetObjectData(obj, serInfo, context, null); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static object GetRealObject(IObjectReference obj, StreamingContext context) + { + return obj.GetRealObject(context); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private object GetUninitializedObject(Type objType) + { + return FormatterServices.GetUninitializedObject(objType); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void SerializationSurrogateGetObjectData(object obj, SerializationInfo serInfo, StreamingContext context) + { + SerializationSurrogate.GetObjectData(obj, serInfo, context); + } + + public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + { + xmlReader.Read(); + Type objType = UnderlyingType; + object obj = objType.IsArray ? Array.CreateInstance(objType.GetElementType(), 0) : GetUninitializedObject(objType); + context.AddNewObject(obj); + string objectId = context.GetObjectId(); + SerializationInfo serInfo = context.ReadSerializationInfo(xmlReader, objType); + object newObj = SerializationSurrogateSetObjectData(obj, serInfo, context.GetStreamingContext()); + if (newObj == null) + { + newObj = obj; + } + + if (newObj is IDeserializationCallback) + { + ((IDeserializationCallback)newObj).OnDeserialization(null); + } + + if (newObj is IObjectReference) + { + newObj = GetRealObject((IObjectReference)newObj, context.GetStreamingContext()); + } + + context.ReplaceDeserializedObject(objectId, obj, newObj); + xmlReader.ReadEndElement(); + return newObj; + } + + private class SurrogateDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private readonly ISerializationSurrogate _serializationSurrogate; + + internal SurrogateDataContractCriticalHelper(Type type, ISerializationSurrogate serializationSurrogate) + : base(type) + { + _serializationSurrogate = serializationSurrogate; + DataContract.GetDefaultStableName(DataContract.GetClrTypeFullName(type), out string name, out string ns); + SetDataContractName(CreateQualifiedName(name, ns)); + } + + internal ISerializationSurrogate SerializationSurrogate => _serializationSurrogate; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRef.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRef.cs new file mode 100644 index 0000000..c1328ec --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRef.cs @@ -0,0 +1,24 @@ +using System; + +namespace Compat.Runtime.Serialization +{ + internal class TypeHandleRef + { + private RuntimeTypeHandle _value; + + public TypeHandleRef() + { + } + + public TypeHandleRef(RuntimeTypeHandle value) + { + _value = value; + } + + public RuntimeTypeHandle Value + { + get => _value; + set => _value = value; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRefEqualityComparer.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRefEqualityComparer.cs new file mode 100644 index 0000000..91b15b5 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeHandleRefEqualityComparer.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Compat.Runtime.Serialization +{ + internal class TypeHandleRefEqualityComparer : IEqualityComparer + { + public bool Equals(TypeHandleRef x, TypeHandleRef y) + { + return x.Value.Equals(y.Value); + } + + public int GetHashCode(TypeHandleRef obj) + { + return obj.Value.GetHashCode(); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeInformation.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeInformation.cs new file mode 100644 index 0000000..b905a4f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/TypeInformation.cs @@ -0,0 +1,22 @@ +namespace Compat.Runtime.Serialization +{ + internal sealed class TypeInformation + { + private readonly string _fullTypeName; + private readonly string _assemblyString; + private readonly bool _hasTypeForwardedFrom; + + internal TypeInformation(string fullTypeName, string assemblyString, bool hasTypeForwardedFrom) + { + _fullTypeName = fullTypeName; + _assemblyString = assemblyString; + _hasTypeForwardedFrom = hasTypeForwardedFrom; + } + + internal string FullTypeName => _fullTypeName; + + internal string AssemblyString => _assemblyString; + + internal bool HasTypeForwardedFrom => _hasTypeForwardedFrom; + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlConverter.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlConverter.cs new file mode 100644 index 0000000..da5687e --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlConverter.cs @@ -0,0 +1,1359 @@ +using Compat.Text; +using Compat.Xml; +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal static class XmlConverter + { + public const int MaxDateTimeChars = 64; + public const int MaxInt32Chars = 16; + public const int MaxInt64Chars = 32; + public const int MaxBoolChars = 5; + public const int MaxFloatChars = 16; + public const int MaxDoubleChars = 32; + public const int MaxDecimalChars = 40; + public const int MaxUInt64Chars = 32; + public const int MaxPrimitiveChars = MaxDateTimeChars; + + private static UTF8Encoding _utf8Encoding; + private static UnicodeEncoding _unicodeEncoding; + private static Base64Encoding _base64Encoding; + + public static Base64Encoding Base64Encoding + { + get + { + if (_base64Encoding == null) + { + _base64Encoding = new Base64Encoding(); + } + + return _base64Encoding; + } + } + + private static UTF8Encoding UTF8Encoding + { + get + { + if (_utf8Encoding == null) + { + _utf8Encoding = new UTF8Encoding(false, true); + } + + return _utf8Encoding; + } + } + + private static UnicodeEncoding UnicodeEncoding + { + get + { + if (_unicodeEncoding == null) + { + _unicodeEncoding = new UnicodeEncoding(false, false, true); + } + + return _unicodeEncoding; + } + } + + public static bool ToBoolean(string value) + { + try + { + return XmlConvert.ToBoolean(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception)); + } + } + + public static bool ToBoolean(byte[] buffer, int offset, int count) + { + if (count == 1) + { + byte ch = buffer[offset]; + if (ch == (byte)'1') + { + return true; + } + else if (ch == (byte)'0') + { + return false; + } + } + return ToBoolean(ToString(buffer, offset, count)); + } + + public static int ToInt32(string value) + { + try + { + return XmlConvert.ToInt32(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception)); + } + } + + public static int ToInt32(byte[] buffer, int offset, int count) + { + if (TryParseInt32(buffer, offset, count, out int value)) + { + return value; + } + + return ToInt32(ToString(buffer, offset, count)); + } + + public static long ToInt64(string value) + { + try + { + return XmlConvert.ToInt64(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception)); + } + } + + public static long ToInt64(byte[] buffer, int offset, int count) + { + if (TryParseInt64(buffer, offset, count, out long value)) + { + return value; + } + + return ToInt64(ToString(buffer, offset, count)); + } + + public static float ToSingle(string value) + { + try + { + return XmlConvert.ToSingle(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception)); + } + } + + public static float ToSingle(byte[] buffer, int offset, int count) + { + if (TryParseSingle(buffer, offset, count, out float value)) + { + return value; + } + + return ToSingle(ToString(buffer, offset, count)); + } + + public static double ToDouble(string value) + { + try + { + return XmlConvert.ToDouble(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception)); + } + } + + public static double ToDouble(byte[] buffer, int offset, int count) + { + if (TryParseDouble(buffer, offset, count, out double value)) + { + return value; + } + + return ToDouble(ToString(buffer, offset, count)); + } + + public static decimal ToDecimal(string value) + { + try + { + return XmlConvert.ToDecimal(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception)); + } + } + + public static decimal ToDecimal(byte[] buffer, int offset, int count) + { + return ToDecimal(ToString(buffer, offset, count)); + } + + public static DateTime ToDateTime(long value) + { + try + { + return DateTime.FromBinary(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(ToString(value), "DateTime", exception)); + } + } + + public static DateTime ToDateTime(string value) + { + try + { + return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception)); + } + } + + public static DateTime ToDateTime(byte[] buffer, int offset, int count) + { + if (TryParseDateTime(buffer, offset, count, out DateTime value)) + { + return value; + } + + return ToDateTime(ToString(buffer, offset, count)); + } + + public static UniqueId ToUniqueId(string value) + { + try + { + return new UniqueId(Trim(value)); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception)); + } + } + + public static UniqueId ToUniqueId(byte[] buffer, int offset, int count) + { + return ToUniqueId(ToString(buffer, offset, count)); + } + + public static TimeSpan ToTimeSpan(string value) + { + try + { + return XmlConvert.ToTimeSpan(value); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception)); + } + } + + public static TimeSpan ToTimeSpan(byte[] buffer, int offset, int count) + { + return ToTimeSpan(ToString(buffer, offset, count)); + } + + [SuppressMessage("Reliability", "Reliability113", Justification = "Catching expected exceptions inline instead of calling Fx.CreateGuid to minimize code change")] + public static Guid ToGuid(string value) + { + try + { + return Guid.Parse(Trim(value)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception)); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception)); + } + } + + public static Guid ToGuid(byte[] buffer, int offset, int count) + { + return ToGuid(ToString(buffer, offset, count)); + } + + public static ulong ToUInt64(string value) + { + try + { + return ulong.Parse(value, NumberFormatInfo.InvariantInfo); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception)); + } + } + + public static ulong ToUInt64(byte[] buffer, int offset, int count) + { + return ToUInt64(ToString(buffer, offset, count)); + } + + public static string ToString(byte[] buffer, int offset, int count) + { + try + { + return UTF8Encoding.GetString(buffer, offset, count); + } + catch (DecoderFallbackException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception)); + } + } + + public static string ToStringUnicode(byte[] buffer, int offset, int count) + { + try + { + return UnicodeEncoding.GetString(buffer, offset, count); + } + catch (DecoderFallbackException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception)); + } + } + + + public static byte[] ToBytes(string value) + { + try + { + return UTF8Encoding.GetBytes(value); + } + catch (DecoderFallbackException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(value, exception)); + } + } + + public static int ToChars(byte[] buffer, int offset, int count, char[] chars, int charOffset) + { + try + { + return UTF8Encoding.GetChars(buffer, offset, count, chars, charOffset); + } + catch (DecoderFallbackException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception)); + } + } + + public static string ToString(bool value) { return value ? "true" : "false"; } + public static string ToString(int value) { return XmlConvert.ToString(value); } + public static string ToString(long value) { return XmlConvert.ToString(value); } + public static string ToString(float value) { return XmlConvert.ToString(value); } + public static string ToString(double value) { return XmlConvert.ToString(value); } + public static string ToString(decimal value) { return XmlConvert.ToString(value); } + public static string ToString(TimeSpan value) { return XmlConvert.ToString(value); } + public static string ToString(UniqueId value) { return value.ToString(); } + public static string ToString(Guid value) { return value.ToString(); } + public static string ToString(ulong value) { return value.ToString(NumberFormatInfo.InvariantInfo); } + + public static string ToString(DateTime value) + { + byte[] dateChars = new byte[MaxDateTimeChars]; + int count = ToChars(value, dateChars, 0); + return ToString(dateChars, 0, count); + } + + private static string ToString(object value) + { + if (value is int) + { + return ToString((int)value); + } + else if (value is long) + { + return ToString((long)value); + } + else if (value is float) + { + return ToString((float)value); + } + else if (value is double) + { + return ToString((double)value); + } + else if (value is decimal) + { + return ToString((decimal)value); + } + else if (value is TimeSpan) + { + return ToString((TimeSpan)value); + } + else if (value is UniqueId) + { + return ToString((UniqueId)value); + } + else if (value is Guid) + { + return ToString((Guid)value); + } + else if (value is ulong) + { + return ToString((ulong)value); + } + else if (value is DateTime) + { + return ToString((DateTime)value); + } + else if (value is bool) + { + return ToString((bool)value); + } + else + { + return value.ToString(); + } + } + + public static string ToString(object[] objects) + { + if (objects.Length == 0) + { + return string.Empty; + } + + string value = ToString(objects[0]); + if (objects.Length > 1) + { + StringBuilder sb = new StringBuilder(value); + for (int i = 1; i < objects.Length; i++) + { + sb.Append(' '); + sb.Append(ToString(objects[i])); + } + value = sb.ToString(); + } + return value; + } + + private static bool TryParseInt32(byte[] chars, int offset, int count, out int result) + { + result = 0; + if (count == 0) + { + return false; + } + + int value = 0; + int offsetMax = offset + count; + if (chars[offset] == '-') + { + if (count == 1) + { + return false; + } + + for (int i = offset + 1; i < offsetMax; i++) + { + int digit = (chars[i] - '0'); + if ((uint)digit > 9) + { + return false; + } + + if (value < int.MinValue / 10) + { + return false; + } + + value *= 10; + if (value < int.MinValue + digit) + { + return false; + } + + value -= digit; + } + } + else + { + for (int i = offset; i < offsetMax; i++) + { + int digit = (chars[i] - '0'); + if ((uint)digit > 9) + { + return false; + } + + if (value > int.MaxValue / 10) + { + return false; + } + + value *= 10; + if (value > int.MaxValue - digit) + { + return false; + } + + value += digit; + } + } + result = value; + return true; + } + + private static bool TryParseInt64(byte[] chars, int offset, int count, out long result) + { + result = 0; + if (count < 11) + { + if (!TryParseInt32(chars, offset, count, out int value)) + { + return false; + } + + result = value; + return true; + } + else + { + long value = 0; + int offsetMax = offset + count; + if (chars[offset] == '-') + { + if (count == 1) + { + return false; + } + + for (int i = offset + 1; i < offsetMax; i++) + { + int digit = (chars[i] - '0'); + if ((uint)digit > 9) + { + return false; + } + + if (value < long.MinValue / 10) + { + return false; + } + + value *= 10; + if (value < long.MinValue + digit) + { + return false; + } + + value -= digit; + } + } + else + { + for (int i = offset; i < offsetMax; i++) + { + int digit = (chars[i] - '0'); + if ((uint)digit > 9) + { + return false; + } + + if (value > long.MaxValue / 10) + { + return false; + } + + value *= 10; + if (value > long.MaxValue - digit) + { + return false; + } + + value += digit; + } + } + result = value; + return true; + } + } + + private static bool TryParseSingle(byte[] chars, int offset, int count, out float result) + { + result = 0; + int offsetMax = offset + count; + bool negative = false; + if (offset < offsetMax && chars[offset] == '-') + { + negative = true; + offset++; + count--; + } + if (count < 1 || count > 10) + { + return false; + } + + int value = 0; + int ch; + while (offset < offsetMax) + { + ch = (chars[offset] - '0'); + if (ch == ('.' - '0')) + { + offset++; + int pow10 = 1; + while (offset < offsetMax) + { + ch = chars[offset] - '0'; + if (((uint)ch) >= 10) + { + return false; + } + + pow10 *= 10; + value = value * 10 + ch; + offset++; + } + // More than 8 characters (7 sig figs and a decimal) and int -> float conversion is lossy, so use double + if (count > 8) + { + result = (float)(value / (double)pow10); + } + else + { + result = value / (float)pow10; + } + if (negative) + { + result = -result; + } + + return true; + } + else if (((uint)ch) >= 10) + { + return false; + } + + value = value * 10 + ch; + offset++; + } + // Ten digits w/out a decimal point might've overflowed the int + if (count == 10) + { + return false; + } + + if (negative) + { + result = -value; + } + else + { + result = value; + } + + return true; + } + + private static bool TryParseDouble(byte[] chars, int offset, int count, out double result) + { + result = 0; + int offsetMax = offset + count; + bool negative = false; + if (offset < offsetMax && chars[offset] == '-') + { + negative = true; + offset++; + count--; + } + if (count < 1 || count > 10) + { + return false; + } + + int value = 0; + int ch; + while (offset < offsetMax) + { + ch = (chars[offset] - '0'); + if (ch == ('.' - '0')) + { + offset++; + int pow10 = 1; + while (offset < offsetMax) + { + ch = chars[offset] - '0'; + if (((uint)ch) >= 10) + { + return false; + } + + pow10 *= 10; + value = value * 10 + ch; + offset++; + } + if (negative) + { + result = -(double)value / pow10; + } + else + { + result = (double)value / pow10; + } + + return true; + } + else if (((uint)ch) >= 10) + { + return false; + } + + value = value * 10 + ch; + offset++; + } + // Ten digits w/out a decimal point might've overflowed the int + if (count == 10) + { + return false; + } + + if (negative) + { + result = -value; + } + else + { + result = value; + } + + return true; + } + + private static int ToInt32D2(byte[] chars, int offset) + { + byte ch1 = (byte)(chars[offset + 0] - '0'); + byte ch2 = (byte)(chars[offset + 1] - '0'); + if (ch1 > 9 || ch2 > 9) + { + return -1; + } + + return 10 * ch1 + ch2; + } + + private static int ToInt32D4(byte[] chars, int offset, int count) + { + return ToInt32D7(chars, offset, count); + } + + private static int ToInt32D7(byte[] chars, int offset, int count) + { + int value = 0; + for (int i = 0; i < count; i++) + { + byte ch = (byte)(chars[offset + i] - '0'); + if (ch > 9) + { + return -1; + } + + value = value * 10 + ch; + } + return value; + } + + private static bool TryParseDateTime(byte[] chars, int offset, int count, out DateTime result) + { + int offsetMax = offset + count; + result = DateTime.MaxValue; + + if (count < 19) + { + return false; + } + + // 1 2 3 + // 012345678901234567890123456789012 + // "yyyy-MM-ddTHH:mm:ss" + // "yyyy-MM-ddTHH:mm:ss.fffffff" + // "yyyy-MM-ddTHH:mm:ss.fffffffZ" + // "yyyy-MM-ddTHH:mm:ss.fffffff+xx:yy" + // "yyyy-MM-ddTHH:mm:ss.fffffff-xx:yy" + if (chars[offset + 4] != '-' || chars[offset + 7] != '-' || chars[offset + 10] != 'T' || + chars[offset + 13] != ':' || chars[offset + 16] != ':') + { + return false; + } + + int year = ToInt32D4(chars, offset + 0, 4); + int month = ToInt32D2(chars, offset + 5); + int day = ToInt32D2(chars, offset + 8); + int hour = ToInt32D2(chars, offset + 11); + int minute = ToInt32D2(chars, offset + 14); + int second = ToInt32D2(chars, offset + 17); + + if ((year | month | day | hour | minute | second) < 0) + { + return false; + } + + DateTimeKind kind = DateTimeKind.Unspecified; + offset += 19; + + int ticks = 0; + if (offset < offsetMax && chars[offset] == '.') + { + offset++; + int digitOffset = offset; + while (offset < offsetMax) + { + byte ch = chars[offset]; + if (ch < '0' || ch > '9') + { + break; + } + + offset++; + } + int digitCount = offset - digitOffset; + if (digitCount < 1 || digitCount > 7) + { + return false; + } + + ticks = ToInt32D7(chars, digitOffset, digitCount); + if (ticks < 0) + { + return false; + } + + for (int i = digitCount; i < 7; ++i) + { + ticks *= 10; + } + } + + bool isLocal = false; + int hourDelta = 0; + int minuteDelta = 0; + if (offset < offsetMax) + { + byte ch = chars[offset]; + if (ch == 'Z') + { + offset++; + kind = DateTimeKind.Utc; + } + else if (ch == '+' || ch == '-') + { + offset++; + if (offset + 5 > offsetMax || chars[offset + 2] != ':') + { + return false; + } + + kind = DateTimeKind.Utc; + isLocal = true; + hourDelta = ToInt32D2(chars, offset); + minuteDelta = ToInt32D2(chars, offset + 3); + if ((hourDelta | minuteDelta) < 0) + { + return false; + } + + if (ch == '+') + { + hourDelta = -hourDelta; + minuteDelta = -minuteDelta; + } + offset += 5; + } + } + if (offset < offsetMax) + { + return false; + } + + DateTime value; + try + { + value = new DateTime(year, month, day, hour, minute, second, kind); + } + catch (ArgumentException) + { + return false; + } + + if (ticks > 0) + { + value = value.AddTicks(ticks); + } + if (isLocal) + { + try + { + TimeSpan ts = new TimeSpan(hourDelta, minuteDelta, 0); + if (hourDelta >= 0 && (value < DateTime.MaxValue - ts) || + hourDelta < 0 && (value > DateTime.MinValue - ts)) + { + value = value.Add(ts).ToLocalTime(); + } + else + { + value = value.ToLocalTime().Add(ts); + } + } + catch (ArgumentOutOfRangeException) // Overflow + { + return false; + } + } + + result = value; + return true; + } + + public static int ToChars(bool value, byte[] buffer, int offset) + { + if (value) + { + buffer[offset + 0] = (byte)'t'; + buffer[offset + 1] = (byte)'r'; + buffer[offset + 2] = (byte)'u'; + buffer[offset + 3] = (byte)'e'; + return 4; + } + else + { + buffer[offset + 0] = (byte)'f'; + buffer[offset + 1] = (byte)'a'; + buffer[offset + 2] = (byte)'l'; + buffer[offset + 3] = (byte)'s'; + buffer[offset + 4] = (byte)'e'; + return 5; + } + } + + // Works left from offset + public static int ToCharsR(int value, byte[] chars, int offset) + { + int count = 0; + if (value >= 0) + { + while (value >= 10) + { + int valueDiv10 = value / 10; + count++; + chars[--offset] = (byte)('0' + (value - valueDiv10 * 10)); + value = valueDiv10; + } + chars[--offset] = (byte)('0' + value); + count++; + } + else + { + while (value <= -10) + { + int valueDiv10 = value / 10; + count++; + chars[--offset] = (byte)('0' - (value - valueDiv10 * 10)); + value = valueDiv10; + } + chars[--offset] = (byte)('0' - value); + chars[--offset] = (byte)'-'; + count += 2; + } + return count; + } + + public static int ToChars(int value, byte[] chars, int offset) + { + int count = ToCharsR(value, chars, offset + MaxInt32Chars); + Buffer.BlockCopy(chars, offset + MaxInt32Chars - count, chars, offset, count); + return count; + } + + public static int ToCharsR(long value, byte[] chars, int offset) + { + int count = 0; + if (value >= 0) + { + while (value > int.MaxValue) + { + long valueDiv10 = value / 10; + count++; + chars[--offset] = (byte)('0' + (int)(value - valueDiv10 * 10)); + value = valueDiv10; + } + } + else + { + while (value < int.MinValue) + { + long valueDiv10 = value / 10; + count++; + chars[--offset] = (byte)('0' - (int)(value - valueDiv10 * 10)); + value = valueDiv10; + } + } + Fx.Assert(value >= int.MinValue && value <= int.MaxValue, ""); + return count + ToCharsR((int)value, chars, offset); + } + + public static int ToChars(long value, byte[] chars, int offset) + { + int count = ToCharsR(value, chars, offset + MaxInt64Chars); + Buffer.BlockCopy(chars, offset + MaxInt64Chars - count, chars, offset, count); + return count; + } + + private static unsafe bool IsNegativeZero(float value) + { + // Simple equals function will report that -0 is equal to +0, so compare bits instead + float negativeZero = -0e0F; + return (*(int*)&value == *(int*)&negativeZero); + } + + private static unsafe bool IsNegativeZero(double value) + { + // Simple equals function will report that -0 is equal to +0, so compare bits instead + double negativeZero = -0e0; + return (*(long*)&value == *(long*)&negativeZero); + } + + private static int ToInfinity(bool isNegative, byte[] buffer, int offset) + { + if (isNegative) + { + buffer[offset + 0] = (byte)'-'; + buffer[offset + 1] = (byte)'I'; + buffer[offset + 2] = (byte)'N'; + buffer[offset + 3] = (byte)'F'; + return 4; + } + else + { + buffer[offset + 0] = (byte)'I'; + buffer[offset + 1] = (byte)'N'; + buffer[offset + 2] = (byte)'F'; + return 3; + } + } + + private static int ToZero(bool isNegative, byte[] buffer, int offset) + { + if (isNegative) + { + buffer[offset + 0] = (byte)'-'; + buffer[offset + 1] = (byte)'0'; + return 2; + } + else + { + buffer[offset] = (byte)'0'; + return 1; + } + } + + public static int ToChars(double value, byte[] buffer, int offset) + { + if (double.IsInfinity(value)) + { + return ToInfinity(double.IsNegativeInfinity(value), buffer, offset); + } + + if (value == 0.0) + { + return ToZero(IsNegativeZero(value), buffer, offset); + } + + return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset); + } + + public static int ToChars(float value, byte[] buffer, int offset) + { + if (float.IsInfinity(value)) + { + return ToInfinity(float.IsNegativeInfinity(value), buffer, offset); + } + + if (value == 0.0) + { + return ToZero(IsNegativeZero(value), buffer, offset); + } + + return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset); + } + + public static int ToChars(decimal value, byte[] buffer, int offset) + { + return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset); + } + + public static int ToChars(ulong value, byte[] buffer, int offset) + { + return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset); + } + + private static int ToAsciiChars(string s, byte[] buffer, int offset) + { + for (int i = 0; i < s.Length; i++) + { + Fx.Assert(s[i] < 128, ""); + buffer[offset++] = (byte)s[i]; + } + return s.Length; + } + + private static int ToCharsD2(int value, byte[] chars, int offset) + { + Fx.Assert(value >= 0 && value < 100, ""); + if (value < 10) + { + chars[offset + 0] = (byte)'0'; + chars[offset + 1] = (byte)('0' + value); + } + else + { + int valueDiv10 = value / 10; + chars[offset + 0] = (byte)('0' + valueDiv10); + chars[offset + 1] = (byte)('0' + value - valueDiv10 * 10); + } + return 2; + } + + private static int ToCharsD4(int value, byte[] chars, int offset) + { + Fx.Assert(value >= 0 && value < 10000, ""); + ToCharsD2(value / 100, chars, offset + 0); + ToCharsD2(value % 100, chars, offset + 2); + return 4; + } + + private static int ToCharsD7(int value, byte[] chars, int offset) + { + Fx.Assert(value >= 0 && value < 10000000, ""); + int zeroCount = 7 - ToCharsR(value, chars, offset + 7); + for (int i = 0; i < zeroCount; i++) + { + chars[offset + i] = (byte)'0'; + } + + int count = 7; + while (count > 0 && chars[offset + count - 1] == '0') + { + count--; + } + + return count; + } + + public static int ToChars(DateTime value, byte[] chars, int offset) + { + const long TicksPerMillisecond = 10000; + const long TicksPerSecond = TicksPerMillisecond * 1000; + int offsetMin = offset; + // "yyyy-MM-ddTHH:mm:ss.fffffff"; + offset += ToCharsD4(value.Year, chars, offset); + chars[offset++] = (byte)'-'; + offset += ToCharsD2(value.Month, chars, offset); + chars[offset++] = (byte)'-'; + offset += ToCharsD2(value.Day, chars, offset); + chars[offset++] = (byte)'T'; + offset += ToCharsD2(value.Hour, chars, offset); + chars[offset++] = (byte)':'; + offset += ToCharsD2(value.Minute, chars, offset); + chars[offset++] = (byte)':'; + offset += ToCharsD2(value.Second, chars, offset); + int ms = (int)(value.Ticks % TicksPerSecond); + if (ms != 0) + { + chars[offset++] = (byte)'.'; + offset += ToCharsD7(ms, chars, offset); + } + switch (value.Kind) + { + case DateTimeKind.Unspecified: + break; + case DateTimeKind.Local: + // +"zzzzzz"; + TimeSpan ts = TimeZoneInfo.Local.GetUtcOffset(value); + if (ts.Ticks < 0) + { + chars[offset++] = (byte)'-'; + } + else + { + chars[offset++] = (byte)'+'; + } + + offset += ToCharsD2(Math.Abs(ts.Hours), chars, offset); + chars[offset++] = (byte)':'; + offset += ToCharsD2(Math.Abs(ts.Minutes), chars, offset); + break; + case DateTimeKind.Utc: + // +"Z" + chars[offset++] = (byte)'Z'; + break; + default: + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); + } + return offset - offsetMin; + } + + public static bool IsWhitespace(string s) + { + for (int i = 0; i < s.Length; i++) + { + if (!IsWhitespace(s[i])) + { + return false; + } + } + return true; + } + + public static bool IsWhitespace(char ch) + { + return (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')); + } + + public static string StripWhitespace(string s) + { + int count = s.Length; + for (int i = 0; i < s.Length; i++) + { + if (IsWhitespace(s[i])) + { + count--; + } + } + if (count == s.Length) + { + return s; + } + + char[] chars = new char[count]; + count = 0; + for (int i = 0; i < s.Length; i++) + { + char ch = s[i]; + if (!IsWhitespace(ch)) + { + chars[count++] = ch; + } + } + return new string(chars); + } + + private static string Trim(string s) + { + int i; + for (i = 0; i < s.Length && IsWhitespace(s[i]); i++) + { + ; + } + + int j; + for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--) + { + ; + } + + if (i == 0 && j == s.Length) + { + return s; + } + else if (j == 0) + { + return string.Empty; + } + else + { + return s.Substring(i, j - i); + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataContract.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataContract.cs new file mode 100644 index 0000000..48306e7 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataContract.cs @@ -0,0 +1,370 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Security; +using System.Threading; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + internal delegate IXmlSerializable CreateXmlSerializableDelegate(); + + internal sealed class XmlDataContract : DataContract + { + private readonly XmlDataContractCriticalHelper _helper; + + internal XmlDataContract() + : base(new XmlDataContractCriticalHelper()) + { + _helper = base.Helper as XmlDataContractCriticalHelper; + } + + internal XmlDataContract(Type type) + : base(new XmlDataContractCriticalHelper(type)) + { + _helper = base.Helper as XmlDataContractCriticalHelper; + } + + internal override DataContractDictionary KnownDataContracts + { + get => _helper.KnownDataContracts; + set => _helper.KnownDataContracts = value; + } + + internal XmlSchemaType XsdType + { + get => _helper.XsdType; + set => _helper.XsdType = value; + } + + internal bool IsAnonymous => _helper.IsAnonymous; + + internal override bool HasRoot + { + get => _helper.HasRoot; + set => _helper.HasRoot = value; + } + + internal override XmlDictionaryString TopLevelElementName + { + get => _helper.TopLevelElementName; + set => _helper.TopLevelElementName = value; + } + + internal override XmlDictionaryString TopLevelElementNamespace + { + get => _helper.TopLevelElementNamespace; + set => _helper.TopLevelElementNamespace = value; + } + + internal bool IsTopLevelElementNullable + { + get => _helper.IsTopLevelElementNullable; + set => _helper.IsTopLevelElementNullable = value; + } + + internal bool IsTypeDefinedOnImport + { + get => _helper.IsTypeDefinedOnImport; + set => _helper.IsTypeDefinedOnImport = value; + } + + internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate + { + get + { + if (_helper.CreateXmlSerializableDelegate == null) + { + lock (this) + { + if (_helper.CreateXmlSerializableDelegate == null) + { + CreateXmlSerializableDelegate tempCreateXmlSerializable = GenerateCreateXmlSerializableDelegate(); + Thread.MemoryBarrier(); + _helper.CreateXmlSerializableDelegate = tempCreateXmlSerializable; + } + } + } + return _helper.CreateXmlSerializableDelegate; + } + } + + internal override bool CanContainReferences => false; + + internal override bool IsBuiltInDataContract => UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray; + + private class XmlDataContractCriticalHelper : DataContract.DataContractCriticalHelper + { + private DataContractDictionary knownDataContracts; + private bool isKnownTypeAttributeChecked; + private XmlDictionaryString topLevelElementName; + private XmlDictionaryString topLevelElementNamespace; + private bool isTopLevelElementNullable; + private bool isTypeDefinedOnImport; + private XmlSchemaType xsdType; + private bool hasRoot; + private CreateXmlSerializableDelegate createXmlSerializable; + + internal XmlDataContractCriticalHelper() + { + } + + internal XmlDataContractCriticalHelper(Type type) + : base(type) + { + if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.IXmlSerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type)))); + } + + if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.IXmlSerializableCannotHaveCollectionDataContract, DataContract.GetClrTypeFullName(type)))); + } + + SchemaExporter.GetXmlTypeInfo(type, out XmlQualifiedName stableName, out XmlSchemaType xsdType, out bool hasRoot); + + StableName = stableName; + XsdType = xsdType; + HasRoot = hasRoot; + XmlDictionary dictionary = new XmlDictionary(); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); + object[] xmlRootAttributes = (UnderlyingType == null) ? null : UnderlyingType.GetCustomAttributes(Globals.TypeOfXmlRootAttribute, false); + if (xmlRootAttributes == null || xmlRootAttributes.Length == 0) + { + if (hasRoot) + { + topLevelElementName = Name; + topLevelElementNamespace = (StableName.Namespace == Globals.SchemaNamespace) ? DictionaryGlobals.EmptyString : Namespace; + isTopLevelElementNullable = true; + } + } + else + { + if (hasRoot) + { + XmlRootAttribute xmlRootAttribute = (XmlRootAttribute)xmlRootAttributes[0]; + isTopLevelElementNullable = xmlRootAttribute.IsNullable; + string elementName = xmlRootAttribute.ElementName; + topLevelElementName = (elementName == null || elementName.Length == 0) ? Name : dictionary.Add(DataContract.EncodeLocalName(elementName)); + string elementNs = xmlRootAttribute.Namespace; + topLevelElementNamespace = (elementNs == null || elementNs.Length == 0) ? DictionaryGlobals.EmptyString : dictionary.Add(elementNs); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.IsAnyCannotHaveXmlRoot, DataContract.GetClrTypeFullName(UnderlyingType)))); + } + } + } + + internal override DataContractDictionary KnownDataContracts + { + get + { + if (!isKnownTypeAttributeChecked && UnderlyingType != null) + { + lock (this) + { + if (!isKnownTypeAttributeChecked) + { + knownDataContracts = DataContract.ImportKnownTypeAttributes(UnderlyingType); + Thread.MemoryBarrier(); + isKnownTypeAttributeChecked = true; + } + } + } + return knownDataContracts; + } + set => knownDataContracts = value; + } + + internal XmlSchemaType XsdType + { + get => xsdType; + set => xsdType = value; + } + + internal bool IsAnonymous => xsdType != null; + + internal override bool HasRoot + { + get => hasRoot; + set => hasRoot = value; + } + + internal override XmlDictionaryString TopLevelElementName + { + get => topLevelElementName; + set => topLevelElementName = value; + } + + internal override XmlDictionaryString TopLevelElementNamespace + { + get => topLevelElementNamespace; + set => topLevelElementNamespace = value; + } + + internal bool IsTopLevelElementNullable + { + get => isTopLevelElementNullable; + set => isTopLevelElementNullable = value; + } + + internal bool IsTypeDefinedOnImport + { + get => isTypeDefinedOnImport; + set => isTypeDefinedOnImport = value; + } + + internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate + { + get => createXmlSerializable; + set => createXmlSerializable = value; + } + + } + + private ConstructorInfo GetConstructor() + { + Type type = UnderlyingType; + + if (type.IsValueType) + { + return null; + } + + ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + if (ctor == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.IXmlSerializableMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); + } + + return ctor; + } + + internal void SetTopLevelElementName(XmlQualifiedName elementName) + { + if (elementName != null) + { + XmlDictionary dictionary = new XmlDictionary(); + TopLevelElementName = dictionary.Add(elementName.Name); + TopLevelElementNamespace = dictionary.Add(elementName.Namespace); + } + } + + internal CreateXmlSerializableDelegate GenerateCreateXmlSerializableDelegate() + { + Type type = UnderlyingType; + CodeGenerator ilg = new CodeGenerator(); + bool memberAccessFlag = RequiresMemberAccessForCreate(null); + ilg.BeginMethod("Create" + DataContract.GetClrTypeFullName(type), typeof(CreateXmlSerializableDelegate), memberAccessFlag); + if (type.IsValueType) + { + System.Reflection.Emit.LocalBuilder local = ilg.DeclareLocal(type, type.Name + "Value"); + ilg.Ldloca(local); + ilg.InitObj(type); + ilg.Ldloc(local); + } + else + { + ilg.New(GetConstructor()); + } + ilg.ConvertValue(UnderlyingType, Globals.TypeOfIXmlSerializable); + ilg.Ret(); + return (CreateXmlSerializableDelegate)ilg.EndMethod(); + } + + private bool RequiresMemberAccessForCreate(SecurityException securityException) + { + if (!IsTypeVisible(UnderlyingType)) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format(SR.PartialTrustIXmlSerializableTypeNotPublic, DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + + if (ConstructorRequiresMemberAccess(GetConstructor())) + { + if (securityException != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format(SR.PartialTrustIXmlSerialzableNoPublicConstructor, DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); + } + return true; + } + + return false; + } + + internal override bool Equals(object other, Dictionary checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + { + return true; + } + + XmlDataContract dataContract = other as XmlDataContract; + if (dataContract != null) + { + if (HasRoot != dataContract.HasRoot) + { + return false; + } + + if (IsAnonymous) + { + return dataContract.IsAnonymous; + } + else + { + return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace); + } + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context) + { + if (context == null) + { + XmlObjectSerializerWriteContext.WriteRootIXmlSerializable(xmlWriter, obj); + } + else + { + context.WriteIXmlSerializable(xmlWriter, obj); + } + } + + public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + { + object o; + if (context == null) + { + o = XmlObjectSerializerReadContext.ReadRootIXmlSerializable(xmlReader, this, true /*isMemberType*/); + } + else + { + o = context.ReadIXmlSerializable(xmlReader, this, true /*isMemberType*/); + context.AddNewObject(o); + } + xmlReader.ReadEndElement(); + return o; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataNode.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataNode.cs new file mode 100644 index 0000000..b26f331 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlDataNode.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal class XmlDataNode : DataNode + { + private IList _xmlAttributes; + private IList _xmlChildNodes; + private XmlDocument _ownerDocument; + + internal XmlDataNode() + { + dataType = Globals.TypeOfXmlDataNode; + } + + internal IList XmlAttributes + { + get => _xmlAttributes; + set => _xmlAttributes = value; + } + + internal IList XmlChildNodes + { + get => _xmlChildNodes; + set => _xmlChildNodes = value; + } + + internal XmlDocument OwnerDocument + { + get => _ownerDocument; + set => _ownerDocument = value; + } + + public override void Clear() + { + base.Clear(); + _xmlAttributes = null; + _xmlChildNodes = null; + _ownerDocument = null; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatGeneratorStatics.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatGeneratorStatics.cs new file mode 100644 index 0000000..1ac83ac --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatGeneratorStatics.cs @@ -0,0 +1,1405 @@ +using System; +using System.Collections; +using System.Reflection; +using System.Xml; +using IDeserializationCallback = System.Runtime.Serialization.IDeserializationCallback; +using IExtensibleDataObject = System.Runtime.Serialization.IExtensibleDataObject; +using SerializationException = System.Runtime.Serialization.SerializationException; + +namespace Compat.Runtime.Serialization +{ + internal static class XmlFormatGeneratorStatics + { + private static MethodInfo writeStartElementMethod2; + internal static MethodInfo WriteStartElementMethod2 + { + get + { + if (writeStartElementMethod2 == null) + { + writeStartElementMethod2 = typeof(XmlWriterDelegator).GetMethod( + nameof(XmlWriterDelegator.WriteStartElement), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, + null); + } + + return writeStartElementMethod2; + } + } + + private static MethodInfo writeStartElementMethod3; + internal static MethodInfo WriteStartElementMethod3 + { + get + { + if (writeStartElementMethod3 == null) + { + writeStartElementMethod3 = typeof(XmlWriterDelegator).GetMethod( + nameof(XmlWriterDelegator.WriteStartElement), + Globals.ScanAllMembers, + null, + new Type[] { typeof(string), typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, + null); + } + + return writeStartElementMethod3; + } + } + + private static MethodInfo writeEndElementMethod; + internal static MethodInfo WriteEndElementMethod + { + get + { + if (writeEndElementMethod == null) + { + writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod( + nameof(XmlWriterDelegator.WriteEndElement), + Globals.ScanAllMembers, + null, + new Type[] { }, + null); + } + + return writeEndElementMethod; + } + } + + private static MethodInfo writeNamespaceDeclMethod; + internal static MethodInfo WriteNamespaceDeclMethod + { + get + { + if (writeNamespaceDeclMethod == null) + { + writeNamespaceDeclMethod = typeof(XmlWriterDelegator).GetMethod( + nameof(XmlWriterDelegator.WriteNamespaceDecl), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlDictionaryString) }, + null); + } + + return writeNamespaceDeclMethod; + } + } + + private static PropertyInfo extensionDataProperty; + internal static PropertyInfo ExtensionDataProperty + { + get + { + if (extensionDataProperty == null) + { + extensionDataProperty = typeof(IExtensibleDataObject).GetProperty(nameof(IExtensibleDataObject.ExtensionData)); + } + + return extensionDataProperty; + } + } + + private static MethodInfo boxPointer; + internal static MethodInfo BoxPointer + { + get + { + if (boxPointer == null) + { + boxPointer = typeof(Pointer).GetMethod(nameof(Pointer.Box)); + } + + return boxPointer; + } + } + + private static ConstructorInfo dictionaryEnumeratorCtor; + internal static ConstructorInfo DictionaryEnumeratorCtor + { + get + { + if (dictionaryEnumeratorCtor == null) + { + dictionaryEnumeratorCtor = Globals.TypeOfDictionaryEnumerator.GetConstructor(Globals.ScanAllMembers, null, new Type[] { Globals.TypeOfIDictionaryEnumerator }, null); + } + + return dictionaryEnumeratorCtor; + } + } + + private static MethodInfo ienumeratorMoveNextMethod; + internal static MethodInfo MoveNextMethod + { + get + { + if (ienumeratorMoveNextMethod == null) + { + ienumeratorMoveNextMethod = typeof(IEnumerator).GetMethod(nameof(IEnumerator.MoveNext)); + } + + return ienumeratorMoveNextMethod; + } + } + + private static MethodInfo ienumeratorGetCurrentMethod; + internal static MethodInfo GetCurrentMethod + { + get + { + if (ienumeratorGetCurrentMethod == null) + { + ienumeratorGetCurrentMethod = typeof(IEnumerator).GetProperty(nameof(IEnumerator.Current)).GetGetMethod(); + } + + return ienumeratorGetCurrentMethod; + } + } + + private static MethodInfo getItemContractMethod; + internal static MethodInfo GetItemContractMethod + { + get + { + if (getItemContractMethod == null) + { + getItemContractMethod = typeof(CollectionDataContract).GetProperty( + nameof(CollectionDataContract.ItemContract), + Globals.ScanAllMembers).GetGetMethod(true/*nonPublic*/); + } + + return getItemContractMethod; + } + } + + private static MethodInfo isStartElementMethod2; + internal static MethodInfo IsStartElementMethod2 + { + get + { + if (isStartElementMethod2 == null) + { + isStartElementMethod2 = typeof(XmlReaderDelegator).GetMethod( + nameof(XmlReaderDelegator.IsStartElement), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, + null); + } + + return isStartElementMethod2; + } + } + + + private static MethodInfo isStartElementMethod0; + internal static MethodInfo IsStartElementMethod0 + { + get + { + if (isStartElementMethod0 == null) + { + isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod( + nameof(XmlReaderDelegator.IsStartElement), + Globals.ScanAllMembers, + null, + new Type[] { }, + null); + } + + return isStartElementMethod0; + } + } + + + private static MethodInfo getUninitializedObjectMethod; + internal static MethodInfo GetUninitializedObjectMethod + { + get + { + if (getUninitializedObjectMethod == null) + { + getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod( + nameof(XmlFormatReaderGenerator.UnsafeGetUninitializedObject), + Globals.ScanAllMembers, + null, + new Type[] { typeof(int) }, + null); + } + + return getUninitializedObjectMethod; + } + } + + + private static MethodInfo onDeserializationMethod; + internal static MethodInfo OnDeserializationMethod + { + get + { + if (onDeserializationMethod == null) + { + onDeserializationMethod = typeof(IDeserializationCallback).GetMethod( + nameof(IDeserializationCallback.OnDeserialization)); + } + + return onDeserializationMethod; + } + } + + + private static MethodInfo unboxPointer; + internal static MethodInfo UnboxPointer + { + get + { + if (unboxPointer == null) + { + unboxPointer = typeof(Pointer).GetMethod(nameof(Pointer.Unbox)); + } + + return unboxPointer; + } + } + + + private static PropertyInfo nodeTypeProperty; + internal static PropertyInfo NodeTypeProperty + { + get + { + if (nodeTypeProperty == null) + { + nodeTypeProperty = typeof(XmlReaderDelegator).GetProperty( + nameof(XmlReaderDelegator.NodeType), + Globals.ScanAllMembers); + } + + return nodeTypeProperty; + } + } + + + private static ConstructorInfo serializationExceptionCtor; + internal static ConstructorInfo SerializationExceptionCtor + { + + get + { + if (serializationExceptionCtor == null) + { + serializationExceptionCtor = typeof(SerializationException).GetConstructor(new Type[] { typeof(string) }); + } + + return serializationExceptionCtor; + } + } + + + private static ConstructorInfo extensionDataObjectCtor; + internal static ConstructorInfo ExtensionDataObjectCtor + { + + get + { + if (extensionDataObjectCtor == null) + { + extensionDataObjectCtor = typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, null, new Type[] { }, null); + } + + return extensionDataObjectCtor; + } + } + + + private static ConstructorInfo hashtableCtor; + internal static ConstructorInfo HashtableCtor + { + + get + { + if (hashtableCtor == null) + { + hashtableCtor = Globals.TypeOfHashtable.GetConstructor(Globals.ScanAllMembers, null, Globals.EmptyTypeArray, null); + } + + return hashtableCtor; + } + } + + + private static MethodInfo getStreamingContextMethod; + internal static MethodInfo GetStreamingContextMethod + { + + get + { + if (getStreamingContextMethod == null) + { + getStreamingContextMethod = typeof(XmlObjectSerializerContext).GetMethod( + nameof(XmlObjectSerializerContext.GetStreamingContext), + Globals.ScanAllMembers); + } + + return getStreamingContextMethod; + } + } + + + private static MethodInfo getCollectionMemberMethod; + internal static MethodInfo GetCollectionMemberMethod + { + + get + { + if (getCollectionMemberMethod == null) + { + getCollectionMemberMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetCollectionMember), + Globals.ScanAllMembers); + } + + return getCollectionMemberMethod; + } + } + + + private static MethodInfo storeCollectionMemberInfoMethod; + internal static MethodInfo StoreCollectionMemberInfoMethod + { + + get + { + if (storeCollectionMemberInfoMethod == null) + { + storeCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.StoreCollectionMemberInfo), + Globals.ScanAllMembers, + null, + new Type[] { typeof(object) }, + null); + } + + return storeCollectionMemberInfoMethod; + } + } + + + private static MethodInfo storeIsGetOnlyCollectionMethod; + internal static MethodInfo StoreIsGetOnlyCollectionMethod + { + + get + { + if (storeIsGetOnlyCollectionMethod == null) + { + storeIsGetOnlyCollectionMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.StoreIsGetOnlyCollection), + Globals.ScanAllMembers); + } + + return storeIsGetOnlyCollectionMethod; + } + } + + + private static MethodInfo throwNullValueReturnedForGetOnlyCollectionExceptionMethod; + internal static MethodInfo ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod + { + + get + { + if (throwNullValueReturnedForGetOnlyCollectionExceptionMethod == null) + { + throwNullValueReturnedForGetOnlyCollectionExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException), + Globals.ScanAllMembers); + } + + return throwNullValueReturnedForGetOnlyCollectionExceptionMethod; + } + } + + private static MethodInfo throwArrayExceededSizeExceptionMethod; + internal static MethodInfo ThrowArrayExceededSizeExceptionMethod + { + + get + { + if (throwArrayExceededSizeExceptionMethod == null) + { + throwArrayExceededSizeExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ThrowArrayExceededSizeException), + Globals.ScanAllMembers); + } + + return throwArrayExceededSizeExceptionMethod; + } + } + + + private static MethodInfo incrementItemCountMethod; + internal static MethodInfo IncrementItemCountMethod + { + + get + { + if (incrementItemCountMethod == null) + { + incrementItemCountMethod = typeof(XmlObjectSerializerContext).GetMethod( + nameof(XmlObjectSerializerContext.IncrementItemCount), + Globals.ScanAllMembers); + } + + return incrementItemCountMethod; + } + } + + private static MethodInfo internalDeserializeMethod; + internal static MethodInfo InternalDeserializeMethod + { + + get + { + if (internalDeserializeMethod == null) + { + internalDeserializeMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.InternalDeserialize), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlReaderDelegator), typeof(int), typeof(RuntimeTypeHandle), typeof(string), typeof(string) }, + null); + } + + return internalDeserializeMethod; + } + } + + + private static MethodInfo moveToNextElementMethod; + internal static MethodInfo MoveToNextElementMethod + { + + get + { + if (moveToNextElementMethod == null) + { + moveToNextElementMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.MoveToNextElement), + Globals.ScanAllMembers); + } + + return moveToNextElementMethod; + } + } + + + private static MethodInfo getMemberIndexMethod; + internal static MethodInfo GetMemberIndexMethod + { + + get + { + if (getMemberIndexMethod == null) + { + getMemberIndexMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetMemberIndex), + Globals.ScanAllMembers); + } + + return getMemberIndexMethod; + } + } + + + private static MethodInfo getMemberIndexWithRequiredMembersMethod; + internal static MethodInfo GetMemberIndexWithRequiredMembersMethod + { + + get + { + if (getMemberIndexWithRequiredMembersMethod == null) + { + getMemberIndexWithRequiredMembersMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetMemberIndexWithRequiredMembers), + Globals.ScanAllMembers); + } + + return getMemberIndexWithRequiredMembersMethod; + } + } + + + private static MethodInfo throwRequiredMemberMissingExceptionMethod; + internal static MethodInfo ThrowRequiredMemberMissingExceptionMethod + { + + get + { + if (throwRequiredMemberMissingExceptionMethod == null) + { + throwRequiredMemberMissingExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException), + Globals.ScanAllMembers); + } + + return throwRequiredMemberMissingExceptionMethod; + } + } + + + private static MethodInfo skipUnknownElementMethod; + internal static MethodInfo SkipUnknownElementMethod + { + + get + { + if (skipUnknownElementMethod == null) + { + skipUnknownElementMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.SkipUnknownElement), + Globals.ScanAllMembers); + } + + return skipUnknownElementMethod; + } + } + + + private static MethodInfo readIfNullOrRefMethod; + internal static MethodInfo ReadIfNullOrRefMethod + { + + get + { + if (readIfNullOrRefMethod == null) + { + readIfNullOrRefMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ReadIfNullOrRef), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlReaderDelegator), typeof(Type), typeof(bool) }, + null); + } + + return readIfNullOrRefMethod; + } + } + + + private static MethodInfo readAttributesMethod; + internal static MethodInfo ReadAttributesMethod + { + + get + { + if (readAttributesMethod == null) + { + readAttributesMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ReadAttributes), + Globals.ScanAllMembers); + } + + return readAttributesMethod; + } + } + + + private static MethodInfo resetAttributesMethod; + internal static MethodInfo ResetAttributesMethod + { + + get + { + if (resetAttributesMethod == null) + { + resetAttributesMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ResetAttributes), + Globals.ScanAllMembers); + } + + return resetAttributesMethod; + } + } + + + private static MethodInfo getObjectIdMethod; + internal static MethodInfo GetObjectIdMethod + { + + get + { + if (getObjectIdMethod == null) + { + getObjectIdMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetObjectId), + Globals.ScanAllMembers); + } + + return getObjectIdMethod; + } + } + + + private static MethodInfo getArraySizeMethod; + internal static MethodInfo GetArraySizeMethod + { + + get + { + if (getArraySizeMethod == null) + { + getArraySizeMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetArraySize), + Globals.ScanAllMembers); + } + + return getArraySizeMethod; + } + } + + + private static MethodInfo addNewObjectMethod; + internal static MethodInfo AddNewObjectMethod + { + + get + { + if (addNewObjectMethod == null) + { + addNewObjectMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.AddNewObject), + Globals.ScanAllMembers); + } + + return addNewObjectMethod; + } + } + + + private static MethodInfo addNewObjectWithIdMethod; + internal static MethodInfo AddNewObjectWithIdMethod + { + + get + { + if (addNewObjectWithIdMethod == null) + { + addNewObjectWithIdMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.AddNewObjectWithId), + Globals.ScanAllMembers); + } + + return addNewObjectWithIdMethod; + } + } + + + private static MethodInfo replaceDeserializedObjectMethod; + internal static MethodInfo ReplaceDeserializedObjectMethod + { + + get + { + if (replaceDeserializedObjectMethod == null) + { + replaceDeserializedObjectMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ReplaceDeserializedObject), + Globals.ScanAllMembers); + } + + return replaceDeserializedObjectMethod; + } + } + + + private static MethodInfo getExistingObjectMethod; + internal static MethodInfo GetExistingObjectMethod + { + + get + { + if (getExistingObjectMethod == null) + { + getExistingObjectMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetExistingObject), + Globals.ScanAllMembers); + } + + return getExistingObjectMethod; + } + } + + + private static MethodInfo getRealObjectMethod; + internal static MethodInfo GetRealObjectMethod + { + + get + { + if (getRealObjectMethod == null) + { + getRealObjectMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.GetRealObject), + Globals.ScanAllMembers); + } + + return getRealObjectMethod; + } + } + + + private static MethodInfo readMethod; + internal static MethodInfo ReadMethod + { + + get + { + if (readMethod == null) + { + readMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.Read), + Globals.ScanAllMembers); + } + + return readMethod; + } + } + + + private static MethodInfo ensureArraySizeMethod; + internal static MethodInfo EnsureArraySizeMethod + { + + get + { + if (ensureArraySizeMethod == null) + { + ensureArraySizeMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.EnsureArraySize), + Globals.ScanAllMembers); + } + + return ensureArraySizeMethod; + } + } + + + private static MethodInfo trimArraySizeMethod; + internal static MethodInfo TrimArraySizeMethod + { + + get + { + if (trimArraySizeMethod == null) + { + trimArraySizeMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.TrimArraySize), + Globals.ScanAllMembers); + } + + return trimArraySizeMethod; + } + } + + + private static MethodInfo checkEndOfArrayMethod; + internal static MethodInfo CheckEndOfArrayMethod + { + + get + { + if (checkEndOfArrayMethod == null) + { + checkEndOfArrayMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.CheckEndOfArray), + Globals.ScanAllMembers); + } + + return checkEndOfArrayMethod; + } + } + + + private static MethodInfo getArrayLengthMethod; + internal static MethodInfo GetArrayLengthMethod + { + + get + { + if (getArrayLengthMethod == null) + { + getArrayLengthMethod = Globals.TypeOfArray.GetProperty("Length").GetGetMethod(); + } + + return getArrayLengthMethod; + } + } + + + private static MethodInfo readSerializationInfoMethod; + internal static MethodInfo ReadSerializationInfoMethod + { + + get + { + if (readSerializationInfoMethod == null) + { + readSerializationInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.ReadSerializationInfo), + Globals.ScanAllMembers); + } + + return readSerializationInfoMethod; + } + } + + + private static MethodInfo createUnexpectedStateExceptionMethod; + internal static MethodInfo CreateUnexpectedStateExceptionMethod + { + + get + { + if (createUnexpectedStateExceptionMethod == null) + { + createUnexpectedStateExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod( + nameof(XmlObjectSerializerReadContext.CreateUnexpectedStateException), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlNodeType), typeof(XmlReaderDelegator) }, + null); + } + + return createUnexpectedStateExceptionMethod; + } + } + + + private static MethodInfo internalSerializeReferenceMethod; + internal static MethodInfo InternalSerializeReferenceMethod + { + + get + { + if (internalSerializeReferenceMethod == null) + { + internalSerializeReferenceMethod = typeof(XmlObjectSerializerWriteContext).GetMethod("InternalSerializeReference", Globals.ScanAllMembers); + } + + return internalSerializeReferenceMethod; + } + } + + + private static MethodInfo internalSerializeMethod; + internal static MethodInfo InternalSerializeMethod + { + + get + { + if (internalSerializeMethod == null) + { + internalSerializeMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.InternalSerialize), + Globals.ScanAllMembers); + } + + return internalSerializeMethod; + } + } + + + private static MethodInfo writeNullMethod; + internal static MethodInfo WriteNullMethod + { + + get + { + if (writeNullMethod == null) + { + writeNullMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.WriteNull), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlWriterDelegator), typeof(Type), typeof(bool) }, + null); + } + + return writeNullMethod; + } + } + + + private static MethodInfo incrementArrayCountMethod; + internal static MethodInfo IncrementArrayCountMethod + { + + get + { + if (incrementArrayCountMethod == null) + { + incrementArrayCountMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.IncrementArrayCount), + Globals.ScanAllMembers); + } + + return incrementArrayCountMethod; + } + } + + + private static MethodInfo incrementCollectionCountMethod; + internal static MethodInfo IncrementCollectionCountMethod + { + + get + { + if (incrementCollectionCountMethod == null) + { + incrementCollectionCountMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.IncrementCollectionCount), + Globals.ScanAllMembers, + null, + new Type[] { typeof(XmlWriterDelegator), typeof(ICollection) }, + null); + } + + return incrementCollectionCountMethod; + } + } + + + private static MethodInfo incrementCollectionCountGenericMethod; + internal static MethodInfo IncrementCollectionCountGenericMethod + { + + get + { + if (incrementCollectionCountGenericMethod == null) + { + incrementCollectionCountGenericMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.IncrementCollectionCountGeneric), + Globals.ScanAllMembers); + } + + return incrementCollectionCountGenericMethod; + } + } + + + private static MethodInfo getDefaultValueMethod; + internal static MethodInfo GetDefaultValueMethod + { + + get + { + if (getDefaultValueMethod == null) + { + getDefaultValueMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.GetDefaultValue), + Globals.ScanAllMembers); + } + + return getDefaultValueMethod; + } + } + + + private static MethodInfo getNullableValueMethod; + internal static MethodInfo GetNullableValueMethod + { + + get + { + if (getNullableValueMethod == null) + { + getNullableValueMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.GetNullableValue), + Globals.ScanAllMembers); + } + + return getNullableValueMethod; + } + } + + + private static MethodInfo throwRequiredMemberMustBeEmittedMethod; + internal static MethodInfo ThrowRequiredMemberMustBeEmittedMethod + { + + get + { + if (throwRequiredMemberMustBeEmittedMethod == null) + { + throwRequiredMemberMustBeEmittedMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.ThrowRequiredMemberMustBeEmitted), + Globals.ScanAllMembers); + } + + return throwRequiredMemberMustBeEmittedMethod; + } + } + + + private static MethodInfo getHasValueMethod; + internal static MethodInfo GetHasValueMethod + { + + get + { + if (getHasValueMethod == null) + { + getHasValueMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.GetHasValue), + Globals.ScanAllMembers); + } + + return getHasValueMethod; + } + } + + + private static MethodInfo writeISerializableMethod; + internal static MethodInfo WriteISerializableMethod + { + + get + { + if (writeISerializableMethod == null) + { + writeISerializableMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.WriteISerializable), + Globals.ScanAllMembers); + } + + return writeISerializableMethod; + } + } + + + private static MethodInfo writeExtensionDataMethod; + internal static MethodInfo WriteExtensionDataMethod + { + + get + { + if (writeExtensionDataMethod == null) + { + writeExtensionDataMethod = typeof(XmlObjectSerializerWriteContext).GetMethod( + nameof(XmlObjectSerializerWriteContext.WriteExtensionData), + Globals.ScanAllMembers); + } + + return writeExtensionDataMethod; + } + } + + + private static MethodInfo writeXmlValueMethod; + internal static MethodInfo WriteXmlValueMethod + { + + get + { + if (writeXmlValueMethod == null) + { + writeXmlValueMethod = typeof(DataContract).GetMethod( + nameof(DataContract.WriteXmlValue), + Globals.ScanAllMembers); + } + + return writeXmlValueMethod; + } + } + + + private static MethodInfo readXmlValueMethod; + internal static MethodInfo ReadXmlValueMethod + { + + get + { + if (readXmlValueMethod == null) + { + readXmlValueMethod = typeof(DataContract).GetMethod( + nameof(DataContract.ReadXmlValue), + Globals.ScanAllMembers); + } + + return readXmlValueMethod; + } + } + + + private static MethodInfo throwTypeNotSerializableMethod; + internal static MethodInfo ThrowTypeNotSerializableMethod + { + + get + { + if (throwTypeNotSerializableMethod == null) + { + throwTypeNotSerializableMethod = typeof(DataContract).GetMethod( + nameof(DataContract.ThrowTypeNotSerializable), + Globals.ScanAllMembers); + } + + return throwTypeNotSerializableMethod; + } + } + + + private static PropertyInfo namespaceProperty; + internal static PropertyInfo NamespaceProperty + { + + get + { + if (namespaceProperty == null) + { + namespaceProperty = typeof(DataContract).GetProperty( + nameof(DataContract.Namespace), + Globals.ScanAllMembers); + } + + return namespaceProperty; + } + } + + + private static FieldInfo contractNamespacesField; + internal static FieldInfo ContractNamespacesField + { + + get + { + if (contractNamespacesField == null) + { + contractNamespacesField = typeof(ClassDataContract).GetField( + nameof(ClassDataContract.ContractNamespaces), + Globals.ScanAllMembers); + } + + return contractNamespacesField; + } + } + + + private static FieldInfo memberNamesField; + internal static FieldInfo MemberNamesField + { + + get + { + if (memberNamesField == null) + { + memberNamesField = typeof(ClassDataContract).GetField( + nameof(ClassDataContract.MemberNames), + Globals.ScanAllMembers); + } + + return memberNamesField; + } + } + + + private static MethodInfo extensionDataSetExplicitMethodInfo; + internal static MethodInfo ExtensionDataSetExplicitMethodInfo + { + + get + { + if (extensionDataSetExplicitMethodInfo == null) + { + extensionDataSetExplicitMethodInfo = typeof(System.Runtime.Serialization.IExtensibleDataObject).GetMethod(Globals.ExtensionDataSetMethod); + } + + return extensionDataSetExplicitMethodInfo; + } + } + + + private static PropertyInfo childElementNamespacesProperty; + internal static PropertyInfo ChildElementNamespacesProperty + { + + get + { + if (childElementNamespacesProperty == null) + { + childElementNamespacesProperty = typeof(ClassDataContract).GetProperty( + nameof(ClassDataContract.ChildElementNamespaces), + Globals.ScanAllMembers); + } + + return childElementNamespacesProperty; + } + } + + + private static PropertyInfo collectionItemNameProperty; + internal static PropertyInfo CollectionItemNameProperty + { + + get + { + if (collectionItemNameProperty == null) + { + collectionItemNameProperty = typeof(CollectionDataContract).GetProperty( + nameof(CollectionDataContract.CollectionItemName), + Globals.ScanAllMembers); + } + + return collectionItemNameProperty; + } + } + + + private static PropertyInfo childElementNamespaceProperty; + internal static PropertyInfo ChildElementNamespaceProperty + { + + get + { + if (childElementNamespaceProperty == null) + { + childElementNamespaceProperty = typeof(CollectionDataContract).GetProperty( + nameof(CollectionDataContract.ChildElementNamespace), + Globals.ScanAllMembers); + } + + return childElementNamespaceProperty; + } + } + + + private static MethodInfo getDateTimeOffsetMethod; + internal static MethodInfo GetDateTimeOffsetMethod + { + + get + { + if (getDateTimeOffsetMethod == null) + { + getDateTimeOffsetMethod = typeof(DateTimeOffsetAdapter).GetMethod( + nameof(DateTimeOffsetAdapter.GetDateTimeOffset), + Globals.ScanAllMembers); + } + + return getDateTimeOffsetMethod; + } + } + + + private static MethodInfo getDateTimeOffsetAdapterMethod; + internal static MethodInfo GetDateTimeOffsetAdapterMethod + { + + get + { + if (getDateTimeOffsetAdapterMethod == null) + { + getDateTimeOffsetAdapterMethod = typeof(DateTimeOffsetAdapter).GetMethod( + nameof(DateTimeOffsetAdapter.GetDateTimeOffsetAdapter), + Globals.ScanAllMembers); + } + + return getDateTimeOffsetAdapterMethod; + } + } + + + private static MethodInfo traceInstructionMethod; + internal static MethodInfo TraceInstructionMethod + { + + get + { + if (traceInstructionMethod == null) + { + traceInstructionMethod = typeof(SerializationTrace).GetMethod( + nameof(SerializationTrace.TraceInstruction), + Globals.ScanAllMembers); + } + + return traceInstructionMethod; + } + } + + + private static MethodInfo throwInvalidDataContractExceptionMethod; + internal static MethodInfo ThrowInvalidDataContractExceptionMethod + { + + get + { + if (throwInvalidDataContractExceptionMethod == null) + { + throwInvalidDataContractExceptionMethod = typeof(DataContract).GetMethod( + nameof(DataContract.ThrowInvalidDataContractException), + Globals.ScanAllMembers, + null, + new Type[] { typeof(string), typeof(Type) }, + null); + } + + return throwInvalidDataContractExceptionMethod; + } + } + + + private static PropertyInfo serializeReadOnlyTypesProperty; + internal static PropertyInfo SerializeReadOnlyTypesProperty + { + + get + { + if (serializeReadOnlyTypesProperty == null) + { + serializeReadOnlyTypesProperty = typeof(XmlObjectSerializerWriteContext).GetProperty( + nameof(XmlObjectSerializerWriteContext.SerializeReadOnlyTypes), + Globals.ScanAllMembers); + } + + return serializeReadOnlyTypesProperty; + } + } + + + private static PropertyInfo classSerializationExceptionMessageProperty; + internal static PropertyInfo ClassSerializationExceptionMessageProperty + { + + get + { + if (classSerializationExceptionMessageProperty == null) + { + classSerializationExceptionMessageProperty = typeof(ClassDataContract).GetProperty( + nameof(ClassDataContract.SerializationExceptionMessage), + Globals.ScanAllMembers); + } + + return classSerializationExceptionMessageProperty; + } + } + + + private static PropertyInfo collectionSerializationExceptionMessageProperty; + internal static PropertyInfo CollectionSerializationExceptionMessageProperty + { + + get + { + if (collectionSerializationExceptionMessageProperty == null) + { + collectionSerializationExceptionMessageProperty = typeof(CollectionDataContract).GetProperty( + nameof(CollectionDataContract.SerializationExceptionMessage), + Globals.ScanAllMembers); + } + + return collectionSerializationExceptionMessageProperty; + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatReaderGenerator.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatReaderGenerator.cs new file mode 100644 index 0000000..5fdc264 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -0,0 +1,902 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal delegate object XmlFormatClassReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[] memberNamespaces); + internal delegate object XmlFormatCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract); + internal delegate void XmlFormatGetOnlyCollectionReaderDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString itemName, XmlDictionaryString itemNamespace, CollectionDataContract collectionContract); + + internal sealed class XmlFormatReaderGenerator + { + private readonly CriticalHelper _helper; + + public XmlFormatReaderGenerator() + { + _helper = new CriticalHelper(); + } + + public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract) + { + return _helper.GenerateClassReader(classContract); + } + + public XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract) + { + return _helper.GenerateCollectionReader(collectionContract); + } + + public XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract) + { + return _helper.GenerateGetOnlyCollectionReader(collectionContract); + } + + private class CriticalHelper + { + private CodeGenerator ilg; + private LocalBuilder objectLocal; + private Type objectType; + private ArgBuilder xmlReaderArg; + private ArgBuilder contextArg; + private ArgBuilder memberNamesArg; + private ArgBuilder memberNamespacesArg; + private ArgBuilder collectionContractArg; + + public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract) + { + ilg = new CodeGenerator(); + bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null); + ilg.BeginMethod("Read" + classContract.StableName.Name + "FromXml", Globals.TypeOfXmlFormatClassReaderDelegate, memberAccessFlag); + InitArgs(); + CreateObject(classContract); + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal); + InvokeOnDeserializing(classContract); + LocalBuilder objectId = null; + if (HasFactoryMethod(classContract)) + { + objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead"); + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod); + ilg.Stloc(objectId); + } + if (classContract.IsISerializable) + { + ReadISerializable(classContract); + } + else + { + ReadClass(classContract); + } + + bool isFactoryType = InvokeFactoryMethod(classContract, objectId); + if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType)) + { + ilg.Call(objectLocal, XmlFormatGeneratorStatics.OnDeserializationMethod, null); + } + + InvokeOnDeserialized(classContract); + if (objectId == null || !isFactoryType) + { + ilg.Load(objectLocal); + + // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization. + // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation + // on DateTimeOffset; which does not work in partial trust. + + if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter) + { + ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfDateTimeOffsetAdapter); + ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetMethod); + ilg.ConvertValue(Globals.TypeOfDateTimeOffset, ilg.CurrentMethod.ReturnType); + } + else + { + ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType); + } + } + return (XmlFormatClassReaderDelegate)ilg.EndMethod(); + } + + public XmlFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract) + { + ilg = GenerateCollectionReaderHelper(collectionContract, false /*isGetOnlyCollection*/); + ReadCollection(collectionContract); + ilg.Load(objectLocal); + ilg.ConvertValue(objectLocal.LocalType, ilg.CurrentMethod.ReturnType); + return (XmlFormatCollectionReaderDelegate)ilg.EndMethod(); + } + + public XmlFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract) + { + ilg = GenerateCollectionReaderHelper(collectionContract, true /*isGetOnlyCollection*/); + ReadGetOnlyCollection(collectionContract); + return (XmlFormatGetOnlyCollectionReaderDelegate)ilg.EndMethod(); + } + + private CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract collectionContract, bool isGetOnlyCollection) + { + ilg = new CodeGenerator(); + bool memberAccessFlag = collectionContract.RequiresMemberAccessForRead(null); + if (isGetOnlyCollection) + { + ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + "IsGetOnly", Globals.TypeOfXmlFormatGetOnlyCollectionReaderDelegate, memberAccessFlag); + } + else + { + ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + string.Empty, Globals.TypeOfXmlFormatCollectionReaderDelegate, memberAccessFlag); + } + InitArgs(); + collectionContractArg = ilg.GetArg(4); + return ilg; + } + + private void InitArgs() + { + xmlReaderArg = ilg.GetArg(0); + contextArg = ilg.GetArg(1); + memberNamesArg = ilg.GetArg(2); + memberNamespacesArg = ilg.GetArg(3); + } + + private void CreateObject(ClassDataContract classContract) + { + Type type = objectType = classContract.UnderlyingType; + if (type.IsValueType && !classContract.IsNonAttributedType) + { + type = Globals.TypeOfValueType; + } + + objectLocal = ilg.DeclareLocal(type, "objectDeserialized"); + + if (classContract.UnderlyingType == Globals.TypeOfDBNull) + { + ilg.LoadMember(Globals.TypeOfDBNull.GetField("Value")); + ilg.Stloc(objectLocal); + } + else if (classContract.IsNonAttributedType) + { + if (type.IsValueType) + { + ilg.Ldloca(objectLocal); + ilg.InitObj(type); + } + else + { + ilg.New(classContract.GetNonAttributedTypeConstructor()); + ilg.Stloc(objectLocal); + } + } + else + { + ilg.Call(null, XmlFormatGeneratorStatics.GetUninitializedObjectMethod, DataContract.GetIdForInitialization(classContract)); + ilg.ConvertValue(Globals.TypeOfObject, type); + ilg.Stloc(objectLocal); + } + } + + private void InvokeOnDeserializing(ClassDataContract classContract) + { + if (classContract.BaseContract != null) + { + InvokeOnDeserializing(classContract.BaseContract); + } + + if (classContract.OnDeserializing != null) + { + ilg.LoadAddress(objectLocal); + ilg.ConvertAddress(objectLocal.LocalType, objectType); + ilg.Load(contextArg); + ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod); + ilg.Call(classContract.OnDeserializing); + } + } + + private void InvokeOnDeserialized(ClassDataContract classContract) + { + if (classContract.BaseContract != null) + { + InvokeOnDeserialized(classContract.BaseContract); + } + + if (classContract.OnDeserialized != null) + { + ilg.LoadAddress(objectLocal); + ilg.ConvertAddress(objectLocal.LocalType, objectType); + ilg.Load(contextArg); + ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod); + ilg.Call(classContract.OnDeserialized); + } + } + + private bool HasFactoryMethod(ClassDataContract classContract) + { + return Globals.TypeOfIObjectReference.IsAssignableFrom(classContract.UnderlyingType); + } + + private bool InvokeFactoryMethod(ClassDataContract classContract, LocalBuilder objectId) + { + if (HasFactoryMethod(classContract)) + { + ilg.Load(contextArg); + ilg.LoadAddress(objectLocal); + ilg.ConvertAddress(objectLocal.LocalType, Globals.TypeOfIObjectReference); + ilg.Load(objectId); + ilg.Call(XmlFormatGeneratorStatics.GetRealObjectMethod); + ilg.ConvertValue(Globals.TypeOfObject, ilg.CurrentMethod.ReturnType); + return true; + } + return false; + } + + private void ReadClass(ClassDataContract classContract) + { + if (classContract.HasExtensionData) + { + LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData"); + ilg.New(XmlFormatGeneratorStatics.ExtensionDataObjectCtor); + ilg.Store(extensionDataLocal); + ReadMembers(classContract, extensionDataLocal); + + ClassDataContract currentContract = classContract; + while (currentContract != null) + { + MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod; + if (extensionDataSetMethod != null) + { + ilg.Call(objectLocal, extensionDataSetMethod, extensionDataLocal); + } + + currentContract = currentContract.BaseContract; + } + } + else + { + ReadMembers(classContract, null /*extensionDataLocal*/); + } + } + + private void ReadMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal) + { + int memberCount = classContract.MemberNames.Length; + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, memberCount); + + LocalBuilder memberIndexLocal = ilg.DeclareLocal(Globals.TypeOfInt, "memberIndex", -1); + + bool[] requiredMembers = GetRequiredMembers(classContract, out int firstRequiredMember); + bool hasRequiredMembers = (firstRequiredMember < memberCount); + LocalBuilder requiredIndexLocal = hasRequiredMembers ? ilg.DeclareLocal(Globals.TypeOfInt, "requiredIndex", firstRequiredMember) : null; + + object forReadElements = ilg.For(null, null, null); + ilg.Call(null, XmlFormatGeneratorStatics.MoveToNextElementMethod, xmlReaderArg); + ilg.IfFalseBreak(forReadElements); + if (hasRequiredMembers) + { + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetMemberIndexWithRequiredMembersMethod, xmlReaderArg, memberNamesArg, memberNamespacesArg, memberIndexLocal, requiredIndexLocal, extensionDataLocal); + } + else + { + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetMemberIndexMethod, xmlReaderArg, memberNamesArg, memberNamespacesArg, memberIndexLocal, extensionDataLocal); + } + + if (memberCount > 0) + { + Label[] memberLabels = ilg.Switch(memberCount); + ReadMembers(classContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal); + ilg.EndSwitch(); + } + else + { + ilg.Pop(); + } + ilg.EndFor(); + if (hasRequiredMembers) + { + ilg.If(requiredIndexLocal, Cmp.LessThan, memberCount); + ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMissingExceptionMethod, xmlReaderArg, memberIndexLocal, requiredIndexLocal, memberNamesArg); + ilg.EndIf(); + } + } + + private int ReadMembers(ClassDataContract classContract, bool[] requiredMembers, Label[] memberLabels, LocalBuilder memberIndexLocal, LocalBuilder requiredIndexLocal) + { + int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers(classContract.BaseContract, requiredMembers, + memberLabels, memberIndexLocal, requiredIndexLocal); + + for (int i = 0; i < classContract.Members.Count; i++, memberCount++) + { + DataMember dataMember = classContract.Members[i]; + Type memberType = dataMember.MemberType; + ilg.Case(memberLabels[memberCount], dataMember.Name); + if (dataMember.IsRequired) + { + int nextRequiredIndex = memberCount + 1; + for (; nextRequiredIndex < requiredMembers.Length; nextRequiredIndex++) + { + if (requiredMembers[nextRequiredIndex]) + { + break; + } + } + + ilg.Set(requiredIndexLocal, nextRequiredIndex); + } + + LocalBuilder value = null; + + if (dataMember.IsGetOnlyCollection) + { + ilg.LoadAddress(objectLocal); + ilg.LoadMember(dataMember.MemberInfo); + value = ilg.DeclareLocal(memberType, dataMember.Name + "Value"); + ilg.Stloc(value); + ilg.Call(contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value); + ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace); + } + else + { + value = ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace); + ilg.LoadAddress(objectLocal); + ilg.ConvertAddress(objectLocal.LocalType, objectType); + ilg.Ldloc(value); + ilg.StoreMember(dataMember.MemberInfo); + } + ilg.Set(memberIndexLocal, memberCount); + ilg.EndCase(); + } + return memberCount; + } + + private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequiredMember) + { + int memberCount = contract.MemberNames.Length; + bool[] requiredMembers = new bool[memberCount]; + GetRequiredMembers(contract, requiredMembers); + for (firstRequiredMember = 0; firstRequiredMember < memberCount; firstRequiredMember++) + { + if (requiredMembers[firstRequiredMember]) + { + break; + } + } + + return requiredMembers; + } + + private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) + { + int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers(contract.BaseContract, requiredMembers); + List members = contract.Members; + for (int i = 0; i < members.Count; i++, memberCount++) + { + requiredMembers[memberCount] = members[i].IsRequired; + } + return memberCount; + } + + private void ReadISerializable(ClassDataContract classContract) + { + ConstructorInfo ctor = classContract.GetISerializableConstructor(); + ilg.LoadAddress(objectLocal); + ilg.ConvertAddress(objectLocal.LocalType, objectType); + ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadSerializationInfoMethod, xmlReaderArg, classContract.UnderlyingType); + ilg.Load(contextArg); + ilg.LoadMember(XmlFormatGeneratorStatics.GetStreamingContextMethod); + ilg.Call(ctor); + } + + private LocalBuilder ReadValue(Type type, string name, string ns) + { + LocalBuilder value = ilg.DeclareLocal(type, "valueRead"); + LocalBuilder nullableValue = null; + int nullables = 0; + while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable) + { + nullables++; + type = type.GetGenericArguments()[0]; + } + + PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type); + if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType) + { + LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead"); + ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadAttributesMethod, xmlReaderArg); + ilg.Call(contextArg, XmlFormatGeneratorStatics.ReadIfNullOrRefMethod, xmlReaderArg, type, DataContract.IsTypeSerializable(type)); + ilg.Stloc(objectId); + // Deserialize null + ilg.If(objectId, Cmp.EqualTo, Globals.NullObjectId); + if (nullables != 0) + { + ilg.LoadAddress(value); + ilg.InitObj(value.LocalType); + } + else if (type.IsValueType) + { + ThrowValidationException(SR.Format(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type))); + } + else + { + ilg.Load(null); + ilg.Stloc(value); + } + + // Deserialize value + + // Compare against Globals.NewObjectId, which is set to string.Empty + ilg.ElseIfIsEmptyString(objectId); + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod); + ilg.Stloc(objectId); + if (type.IsValueType) + { + ilg.IfNotIsEmptyString(objectId); + ThrowValidationException(SR.Format(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type))); + ilg.EndIf(); + } + if (nullables != 0) + { + nullableValue = value; + value = ilg.DeclareLocal(type, "innerValueRead"); + } + + if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) + { + ilg.Call(xmlReaderArg, primitiveContract.XmlFormatReaderMethod); + ilg.Stloc(value); + if (!type.IsValueType) + { + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, value); + } + } + else + { + InternalDeserialize(value, type, name, ns); + } + // Deserialize ref + ilg.Else(); + if (type.IsValueType) + { + ThrowValidationException(SR.Format(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type))); + } + else + { + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetExistingObjectMethod, objectId, type, name, ns); + ilg.ConvertValue(Globals.TypeOfObject, type); + ilg.Stloc(value); + } + ilg.EndIf(); + + if (nullableValue != null) + { + ilg.If(objectId, Cmp.NotEqualTo, Globals.NullObjectId); + WrapNullableObject(value, nullableValue, nullables); + ilg.EndIf(); + value = nullableValue; + } + } + else + { + InternalDeserialize(value, type, name, ns); + } + + return value; + } + + private void InternalDeserialize(LocalBuilder value, Type type, string name, string ns) + { + ilg.Load(contextArg); + ilg.Load(xmlReaderArg); + Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type; + ilg.Load(DataContract.GetId(declaredType.TypeHandle)); + ilg.Ldtoken(declaredType); + ilg.Load(name); + ilg.Load(ns); + ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod); + + if (type.IsPointer) + { + ilg.Call(XmlFormatGeneratorStatics.UnboxPointer); + } + else + { + ilg.ConvertValue(Globals.TypeOfObject, type); + } + + ilg.Stloc(value); + } + + private void WrapNullableObject(LocalBuilder innerValue, LocalBuilder outerValue, int nullables) + { + Type innerType = innerValue.LocalType, outerType = outerValue.LocalType; + ilg.LoadAddress(outerValue); + ilg.Load(innerValue); + for (int i = 1; i < nullables; i++) + { + Type type = Globals.TypeOfNullable.MakeGenericType(innerType); + ilg.New(type.GetConstructor(new Type[] { innerType })); + innerType = type; + } + ilg.Call(outerType.GetConstructor(new Type[] { innerType })); + } + + private void ReadCollection(CollectionDataContract collectionContract) + { + Type type = collectionContract.UnderlyingType; + Type itemType = collectionContract.ItemType; + bool isArray = (collectionContract.Kind == CollectionKind.Array); + + ConstructorInfo constructor = collectionContract.Constructor; + + if (type.IsInterface) + { + switch (collectionContract.Kind) + { + case CollectionKind.GenericDictionary: + type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments()); + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + break; + case CollectionKind.Dictionary: + type = Globals.TypeOfHashtable; + constructor = XmlFormatGeneratorStatics.HashtableCtor; + break; + case CollectionKind.Collection: + case CollectionKind.GenericCollection: + case CollectionKind.Enumerable: + case CollectionKind.GenericEnumerable: + case CollectionKind.List: + case CollectionKind.GenericList: + type = itemType.MakeArrayType(); + isArray = true; + break; + } + } + string itemName = collectionContract.ItemName; + string itemNs = collectionContract.StableName.Namespace; + + objectLocal = ilg.DeclareLocal(type, "objectDeserialized"); + if (!isArray) + { + if (type.IsValueType) + { + ilg.Ldloca(objectLocal); + ilg.InitObj(type); + } + else + { + ilg.New(constructor); + ilg.Stloc(objectLocal); + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal); + } + } + + LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize"); + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetArraySizeMethod); + ilg.Stloc(size); + + LocalBuilder objectId = ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead"); + ilg.Call(contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod); + ilg.Stloc(objectId); + + bool canReadPrimitiveArray = false; + if (isArray && TryReadPrimitiveArray(type, itemType, size)) + { + canReadPrimitiveArray = true; + ilg.IfNot(); + } + + ilg.If(size, Cmp.EqualTo, -1); + + LocalBuilder growingCollection = null; + if (isArray) + { + growingCollection = ilg.DeclareLocal(type, "growingCollection"); + ilg.NewArray(itemType, 32); + ilg.Stloc(growingCollection); + } + LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i"); + object forLoop = ilg.For(i, 0, int.MaxValue); + IsStartElement(memberNamesArg, memberNamespacesArg); + ilg.If(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1); + LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs); + if (isArray) + { + MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType); + ilg.Call(null, ensureArraySizeMethod, growingCollection, i); + ilg.Stloc(growingCollection); + ilg.StoreArrayElement(growingCollection, i, value); + } + else + { + StoreCollectionValue(objectLocal, value, collectionContract); + } + + ilg.Else(); + IsEndElement(); + ilg.If(); + ilg.Break(forLoop); + ilg.Else(); + HandleUnexpectedItemInCollection(i); + ilg.EndIf(); + ilg.EndIf(); + + ilg.EndFor(); + if (isArray) + { + MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType); + ilg.Call(null, trimArraySizeMethod, growingCollection, i); + ilg.Stloc(objectLocal); + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal); + } + ilg.Else(); + + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, size); + if (isArray) + { + ilg.NewArray(itemType, size); + ilg.Stloc(objectLocal); + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal); + } + LocalBuilder j = ilg.DeclareLocal(Globals.TypeOfInt, "j"); + ilg.For(j, 0, size); + IsStartElement(memberNamesArg, memberNamespacesArg); + ilg.If(); + LocalBuilder itemValue = ReadCollectionItem(collectionContract, itemType, itemName, itemNs); + if (isArray) + { + ilg.StoreArrayElement(objectLocal, j, itemValue); + } + else + { + StoreCollectionValue(objectLocal, itemValue, collectionContract); + } + + ilg.Else(); + HandleUnexpectedItemInCollection(j); + ilg.EndIf(); + ilg.EndFor(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, memberNamespacesArg); + ilg.EndIf(); + + if (canReadPrimitiveArray) + { + ilg.Else(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, objectLocal); + ilg.EndIf(); + } + } + + private void ReadGetOnlyCollection(CollectionDataContract collectionContract) + { + Type type = collectionContract.UnderlyingType; + Type itemType = collectionContract.ItemType; + bool isArray = (collectionContract.Kind == CollectionKind.Array); + string itemName = collectionContract.ItemName; + string itemNs = collectionContract.StableName.Namespace; + + objectLocal = ilg.DeclareLocal(type, "objectDeserialized"); + ilg.Load(contextArg); + ilg.LoadMember(XmlFormatGeneratorStatics.GetCollectionMemberMethod); + ilg.ConvertValue(Globals.TypeOfObject, type); + ilg.Stloc(objectLocal); + + //check that items are actually going to be deserialized into the collection + IsStartElement(memberNamesArg, memberNamespacesArg); + ilg.If(); + ilg.If(objectLocal, Cmp.EqualTo, null); + ilg.Call(null, XmlFormatGeneratorStatics.ThrowNullValueReturnedForGetOnlyCollectionExceptionMethod, type); + + ilg.Else(); + LocalBuilder size = ilg.DeclareLocal(Globals.TypeOfInt, "arraySize"); + if (isArray) + { + ilg.Load(objectLocal); + ilg.Call(XmlFormatGeneratorStatics.GetArrayLengthMethod); + ilg.Stloc(size); + } + + ilg.Call(contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, objectLocal); + + LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i"); + object forLoop = ilg.For(i, 0, int.MaxValue); + IsStartElement(memberNamesArg, memberNamespacesArg); + ilg.If(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1); + LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs); + if (isArray) + { + ilg.If(size, Cmp.EqualTo, i); + ilg.Call(null, XmlFormatGeneratorStatics.ThrowArrayExceededSizeExceptionMethod, size, type); + ilg.Else(); + ilg.StoreArrayElement(objectLocal, i, value); + ilg.EndIf(); + } + else + { + StoreCollectionValue(objectLocal, value, collectionContract); + } + + ilg.Else(); + IsEndElement(); + ilg.If(); + ilg.Break(forLoop); + ilg.Else(); + HandleUnexpectedItemInCollection(i); + ilg.EndIf(); + ilg.EndIf(); + ilg.EndFor(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, xmlReaderArg, size, memberNamesArg, memberNamespacesArg); + + ilg.EndIf(); + ilg.EndIf(); + } + + private bool TryReadPrimitiveArray(Type type, Type itemType, LocalBuilder size) + { + PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType); + if (primitiveContract == null) + { + return false; + } + + string readArrayMethod = null; + switch (Type.GetTypeCode(itemType)) + { + case TypeCode.Boolean: + readArrayMethod = "TryReadBooleanArray"; + break; + case TypeCode.DateTime: + readArrayMethod = "TryReadDateTimeArray"; + break; + case TypeCode.Decimal: + readArrayMethod = "TryReadDecimalArray"; + break; + case TypeCode.Int32: + readArrayMethod = "TryReadInt32Array"; + break; + case TypeCode.Int64: + readArrayMethod = "TryReadInt64Array"; + break; + case TypeCode.Single: + readArrayMethod = "TryReadSingleArray"; + break; + case TypeCode.Double: + readArrayMethod = "TryReadDoubleArray"; + break; + default: + break; + } + if (readArrayMethod != null) + { + ilg.Load(xmlReaderArg); + ilg.Load(contextArg); + ilg.Load(memberNamesArg); + ilg.Load(memberNamespacesArg); + ilg.Load(size); + ilg.Ldloca(objectLocal); + ilg.Call(typeof(XmlReaderDelegator).GetMethod(readArrayMethod, Globals.ScanAllMembers)); + return true; + } + return false; + } + + private LocalBuilder ReadCollectionItem(CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs) + { + if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary) + { + ilg.Call(contextArg, XmlFormatGeneratorStatics.ResetAttributesMethod); + LocalBuilder value = ilg.DeclareLocal(itemType, "valueRead"); + ilg.Load(collectionContractArg); + ilg.Call(XmlFormatGeneratorStatics.GetItemContractMethod); + ilg.Load(xmlReaderArg); + ilg.Load(contextArg); + ilg.Call(XmlFormatGeneratorStatics.ReadXmlValueMethod); + ilg.ConvertValue(Globals.TypeOfObject, itemType); + ilg.Stloc(value); + return value; + } + else + { + return ReadValue(itemType, itemName, itemNs); + } + } + + private void StoreCollectionValue(LocalBuilder collection, LocalBuilder value, CollectionDataContract collectionContract) + { + if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary) + { + ClassDataContract keyValuePairContract = DataContract.GetDataContract(value.LocalType) as ClassDataContract; + if (keyValuePairContract == null) + { + Fx.Assert("Failed to create contract for KeyValuePair type"); + } + DataMember keyMember = keyValuePairContract.Members[0]; + DataMember valueMember = keyValuePairContract.Members[1]; + LocalBuilder pairKey = ilg.DeclareLocal(keyMember.MemberType, keyMember.Name); + LocalBuilder pairValue = ilg.DeclareLocal(valueMember.MemberType, valueMember.Name); + ilg.LoadAddress(value); + ilg.LoadMember(keyMember.MemberInfo); + ilg.Stloc(pairKey); + ilg.LoadAddress(value); + ilg.LoadMember(valueMember.MemberInfo); + ilg.Stloc(pairValue); + + ilg.Call(collection, collectionContract.AddMethod, pairKey, pairValue); + if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid) + { + ilg.Pop(); + } + } + else + { + ilg.Call(collection, collectionContract.AddMethod, value); + if (collectionContract.AddMethod.ReturnType != Globals.TypeOfVoid) + { + ilg.Pop(); + } + } + } + + private void HandleUnexpectedItemInCollection(LocalBuilder iterator) + { + IsStartElement(); + ilg.If(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.SkipUnknownElementMethod, xmlReaderArg); + ilg.Dec(iterator); + ilg.Else(); + ThrowUnexpectedStateException(XmlNodeType.Element); + ilg.EndIf(); + } + + private void IsStartElement(ArgBuilder nameArg, ArgBuilder nsArg) + { + ilg.Call(xmlReaderArg, XmlFormatGeneratorStatics.IsStartElementMethod2, nameArg, nsArg); + } + + private void IsStartElement() + { + ilg.Call(xmlReaderArg, XmlFormatGeneratorStatics.IsStartElementMethod0); + } + + private void IsEndElement() + { + ilg.Load(xmlReaderArg); + ilg.LoadMember(XmlFormatGeneratorStatics.NodeTypeProperty); + ilg.Load(XmlNodeType.EndElement); + ilg.Ceq(); + } + + private void ThrowUnexpectedStateException(XmlNodeType expectedState) + { + ilg.Call(null, XmlFormatGeneratorStatics.CreateUnexpectedStateExceptionMethod, expectedState, xmlReaderArg); + ilg.Throw(); + } + + private void ThrowValidationException(string msg, params object[] values) + { + if (values != null && values.Length > 0) + { + ilg.CallStringFormat(msg, values); + } + else + { + ilg.Load(msg); + } + + ThrowValidationException(); + } + + private void ThrowValidationException() + { + ilg.New(XmlFormatGeneratorStatics.SerializationExceptionCtor); + ilg.Throw(); + } + + } + + internal static object UnsafeGetUninitializedObject(int id) + { + return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(DataContract.GetDataContractForInitialization(id).TypeForInitialization); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatWriterGenerator.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatWriterGenerator.cs new file mode 100644 index 0000000..cd46c7d --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -0,0 +1,743 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Security; +using System.Security.Permissions; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal delegate void XmlFormatClassWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, ClassDataContract dataContract); + internal delegate void XmlFormatCollectionWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract dataContract); + + internal sealed class XmlFormatWriterGenerator + { + CriticalHelper _helper; + + public XmlFormatWriterGenerator() + { + _helper = new CriticalHelper(); + } + + internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract) + { + return _helper.GenerateClassWriter(classContract); + } + + internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract) + { + return _helper.GenerateCollectionWriter(collectionContract); + } + + class CriticalHelper + { + CodeGenerator ilg; + ArgBuilder xmlWriterArg; + ArgBuilder contextArg; + ArgBuilder dataContractArg; + LocalBuilder objectLocal; + + // Used for classes + LocalBuilder contractNamespacesLocal; + LocalBuilder memberNamesLocal; + LocalBuilder childElementNamespacesLocal; + int typeIndex = 1; + int childElementIndex = 0; + + internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract) + { + ilg = new CodeGenerator(); + bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null); + ilg.BeginMethod("Write" + classContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatClassWriterDelegate, memberAccessFlag); + InitArgs(classContract.UnderlyingType); + if (classContract.IsReadOnlyContract) + { + ThrowIfCannotSerializeReadOnlyTypes(classContract); + } + WriteClass(classContract); + return (XmlFormatClassWriterDelegate)ilg.EndMethod(); + } + + internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract) + { + ilg = new CodeGenerator(); + bool memberAccessFlag = collectionContract.RequiresMemberAccessForWrite(null); + ilg.BeginMethod("Write" + collectionContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatCollectionWriterDelegate, memberAccessFlag); + InitArgs(collectionContract.UnderlyingType); + if (collectionContract.IsReadOnlyContract) + { + ThrowIfCannotSerializeReadOnlyTypes(collectionContract); + } + WriteCollection(collectionContract); + return (XmlFormatCollectionWriterDelegate)ilg.EndMethod(); + } + + void InitArgs(Type objType) + { + xmlWriterArg = ilg.GetArg(0); + contextArg = ilg.GetArg(2); + dataContractArg = ilg.GetArg(3); + + objectLocal = ilg.DeclareLocal(objType, "objSerialized"); + ArgBuilder objectArg = ilg.GetArg(1); + ilg.Load(objectArg); + + // Copy the data from the DataTimeOffset object passed in to the DateTimeOffsetAdapter. + // DateTimeOffsetAdapter is used here for serialization purposes to bypass the ISerializable implementation + // on DateTimeOffset; which does not work in partial trust. + + if (objType == Globals.TypeOfDateTimeOffsetAdapter) + { + ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfDateTimeOffset); + ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetAdapterMethod); + } + else + { + ilg.ConvertValue(objectArg.ArgType, objType); + } + ilg.Stloc(objectLocal); + } + + void ThrowIfCannotSerializeReadOnlyTypes(ClassDataContract classContract) + { + ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.ClassSerializationExceptionMessageProperty); + } + + void ThrowIfCannotSerializeReadOnlyTypes(CollectionDataContract classContract) + { + ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.CollectionSerializationExceptionMessageProperty); + } + + void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExceptionMessageProperty) + { + ilg.Load(contextArg); + ilg.LoadMember(XmlFormatGeneratorStatics.SerializeReadOnlyTypesProperty); + ilg.IfNot(); + ilg.Load(dataContractArg); + ilg.LoadMember(serializationExceptionMessageProperty); + ilg.Load(null); + ilg.Call(XmlFormatGeneratorStatics.ThrowInvalidDataContractExceptionMethod); + ilg.EndIf(); + } + + void InvokeOnSerializing(ClassDataContract classContract) + { + if (classContract.BaseContract != null) + InvokeOnSerializing(classContract.BaseContract); + if (classContract.OnSerializing != null) + { + ilg.LoadAddress(objectLocal); + ilg.Load(contextArg); + ilg.Call(XmlFormatGeneratorStatics.GetStreamingContextMethod); + ilg.Call(classContract.OnSerializing); + } + } + + void InvokeOnSerialized(ClassDataContract classContract) + { + if (classContract.BaseContract != null) + InvokeOnSerialized(classContract.BaseContract); + if (classContract.OnSerialized != null) + { + ilg.LoadAddress(objectLocal); + ilg.Load(contextArg); + ilg.Call(XmlFormatGeneratorStatics.GetStreamingContextMethod); + ilg.Call(classContract.OnSerialized); + } + } + + void WriteClass(ClassDataContract classContract) + { + InvokeOnSerializing(classContract); + + if (classContract.IsISerializable) + ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteISerializableMethod, xmlWriterArg, objectLocal); + else + { + if (classContract.ContractNamespaces.Length > 1) + { + contractNamespacesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "contractNamespaces"); + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.ContractNamespacesField); + ilg.Store(contractNamespacesLocal); + } + + memberNamesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "memberNames"); + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.MemberNamesField); + ilg.Store(memberNamesLocal); + + for (int i = 0; i < classContract.ChildElementNamespaces.Length; i++) + { + if (classContract.ChildElementNamespaces[i] != null) + { + childElementNamespacesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "childElementNamespaces"); + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespacesProperty); + ilg.Store(childElementNamespacesLocal); + } + } + + if (classContract.HasExtensionData) + { + LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData"); + ilg.Load(objectLocal); + ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfIExtensibleDataObject); + ilg.LoadMember(XmlFormatGeneratorStatics.ExtensionDataProperty); + ilg.Store(extensionDataLocal); + ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, xmlWriterArg, extensionDataLocal, -1); + WriteMembers(classContract, extensionDataLocal, classContract); + } + else + WriteMembers(classContract, null, classContract); + } + InvokeOnSerialized(classContract); + } + + int WriteMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal, ClassDataContract derivedMostClassContract) + { + int memberCount = (classContract.BaseContract == null) ? 0 : + WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract); + + LocalBuilder namespaceLocal = ilg.DeclareLocal(typeof(XmlDictionaryString), "ns"); + if (contractNamespacesLocal == null) + { + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty); + } + else + ilg.LoadArrayElement(contractNamespacesLocal, typeIndex - 1); + ilg.Store(namespaceLocal); + + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, classContract.Members.Count); + + for (int i = 0; i < classContract.Members.Count; i++, memberCount++) + { + DataMember member = classContract.Members[i]; + Type memberType = member.MemberType; + LocalBuilder memberValue = null; + if (member.IsGetOnlyCollection) + { + ilg.Load(contextArg); + ilg.Call(XmlFormatGeneratorStatics.StoreIsGetOnlyCollectionMethod); + } + if (!member.EmitDefaultValue) + { + memberValue = LoadMemberValue(member); + ilg.IfNotDefaultValue(memberValue); + } + bool writeXsiType = CheckIfMemberHasConflict(member, classContract, derivedMostClassContract); + if (writeXsiType || !TryWritePrimitive(memberType, memberValue, member.MemberInfo, null /*arrayItemIndex*/, namespaceLocal, null /*nameLocal*/, i + childElementIndex)) + { + WriteStartElement(memberType, classContract.Namespace, namespaceLocal, null /*nameLocal*/, i + childElementIndex); + if (classContract.ChildElementNamespaces[i + childElementIndex] != null) + { + ilg.Load(xmlWriterArg); + ilg.LoadArrayElement(childElementNamespacesLocal, i + childElementIndex); + ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod); + } + if (memberValue == null) + memberValue = LoadMemberValue(member); + WriteValue(memberValue, writeXsiType); + WriteEndElement(); + } + if (classContract.HasExtensionData) + ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, xmlWriterArg, extensionDataLocal, memberCount); + if (!member.EmitDefaultValue) + { + if (member.IsRequired) + { + ilg.Else(); + ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMustBeEmittedMethod, member.Name, classContract.UnderlyingType); + } + ilg.EndIf(); + } + + } + + typeIndex++; + childElementIndex += classContract.Members.Count; + return memberCount; + } + + private LocalBuilder LoadMemberValue(DataMember member) + { + ilg.LoadAddress(objectLocal); + ilg.LoadMember(member.MemberInfo); + LocalBuilder memberValue = ilg.DeclareLocal(member.MemberType, member.Name + "Value"); + ilg.Stloc(memberValue); + return memberValue; + } + + void WriteCollection(CollectionDataContract collectionContract) + { + LocalBuilder itemNamespace = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemNamespace"); + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty); + ilg.Store(itemNamespace); + + LocalBuilder itemName = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemName"); + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.CollectionItemNameProperty); + ilg.Store(itemName); + + if (collectionContract.ChildElementNamespace != null) + { + ilg.Load(xmlWriterArg); + ilg.Load(dataContractArg); + ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespaceProperty); + ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod); + } + + if (collectionContract.Kind == CollectionKind.Array) + { + Type itemType = collectionContract.ItemType; + LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i"); + + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementArrayCountMethod, xmlWriterArg, objectLocal); + + if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, objectLocal, itemName, itemNamespace)) + { + ilg.For(i, 0, objectLocal); + if (!TryWritePrimitive(itemType, null /*value*/, null /*memberInfo*/, i /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/)) + { + WriteStartElement(itemType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/); + ilg.LoadArrayElement(objectLocal, i); + LocalBuilder memberValue = ilg.DeclareLocal(itemType, "memberValue"); + ilg.Stloc(memberValue); + WriteValue(memberValue, false /*writeXsiType*/); + WriteEndElement(); + } + ilg.EndFor(); + } + } + else + { + MethodInfo incrementCollectionCountMethod = null; + switch (collectionContract.Kind) + { + case CollectionKind.Collection: + case CollectionKind.List: + case CollectionKind.Dictionary: + incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod; + break; + case CollectionKind.GenericCollection: + case CollectionKind.GenericList: + incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType); + break; + case CollectionKind.GenericDictionary: + incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments())); + break; + } + if (incrementCollectionCountMethod != null) + { + ilg.Call(contextArg, incrementCollectionCountMethod, xmlWriterArg, objectLocal); + } + + bool isDictionary = false, isGenericDictionary = false; + Type enumeratorType = null; + Type[] keyValueTypes = null; + if (collectionContract.Kind == CollectionKind.GenericDictionary) + { + isGenericDictionary = true; + keyValueTypes = collectionContract.ItemType.GetGenericArguments(); + enumeratorType = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes); + } + else if (collectionContract.Kind == CollectionKind.Dictionary) + { + isDictionary = true; + keyValueTypes = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject }; + enumeratorType = Globals.TypeOfDictionaryEnumerator; + } + else + { + enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType; + } + MethodInfo moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null); + if (moveNextMethod == null || getCurrentMethod == null) + { + if (enumeratorType.IsInterface) + { + if (moveNextMethod == null) + moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod; + if (getCurrentMethod == null) + getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod; + } + else + { + Type ienumeratorInterface = Globals.TypeOfIEnumerator; + CollectionKind kind = collectionContract.Kind; + if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable) + { + Type[] interfaceTypes = enumeratorType.GetInterfaces(); + foreach (Type interfaceType in interfaceTypes) + { + if (interfaceType.IsGenericType + && interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric + && interfaceType.GetGenericArguments()[0] == collectionContract.ItemType) + { + ienumeratorInterface = interfaceType; + break; + } + } + } + if (moveNextMethod == null) + moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface); + if (getCurrentMethod == null) + getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface); + } + } + Type elementType = getCurrentMethod.ReturnType; + LocalBuilder currentValue = ilg.DeclareLocal(elementType, "currentValue"); + + LocalBuilder enumerator = ilg.DeclareLocal(enumeratorType, "enumerator"); + ilg.Call(objectLocal, collectionContract.GetEnumeratorMethod); + if (isDictionary) + { + ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator); + ilg.New(XmlFormatGeneratorStatics.DictionaryEnumeratorCtor); + } + else if (isGenericDictionary) + { + Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes)); + ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null); + ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam); + ilg.New(dictEnumCtor); + } + ilg.Stloc(enumerator); + + ilg.ForEach(currentValue, elementType, enumeratorType, enumerator, getCurrentMethod); + if (incrementCollectionCountMethod == null) + { + ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1); + } + if (!TryWritePrimitive(elementType, currentValue, null /*memberInfo*/, null /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/)) + { + WriteStartElement(elementType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/); + + if (isGenericDictionary || isDictionary) + { + ilg.Call(dataContractArg, XmlFormatGeneratorStatics.GetItemContractMethod); + ilg.Load(xmlWriterArg); + ilg.Load(currentValue); + ilg.ConvertValue(currentValue.LocalType, Globals.TypeOfObject); + ilg.Load(contextArg); + ilg.Call(XmlFormatGeneratorStatics.WriteXmlValueMethod); + } + else + { + WriteValue(currentValue, false /*writeXsiType*/); + } + WriteEndElement(); + } + ilg.EndForEach(moveNextMethod); + } + } + + bool TryWritePrimitive(Type type, LocalBuilder value, MemberInfo memberInfo, LocalBuilder arrayItemIndex, LocalBuilder ns, LocalBuilder name, int nameIndex) + { + PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type); + if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject) + return false; + + // load xmlwriter + if (type.IsValueType) + { + ilg.Load(xmlWriterArg); + } + else + { + ilg.Load(contextArg); + ilg.Load(xmlWriterArg); + } + // load primitive value + if (value != null) + { + ilg.Load(value); + } + else if (memberInfo != null) + { + ilg.LoadAddress(objectLocal); + ilg.LoadMember(memberInfo); + } + else + { + ilg.LoadArrayElement(objectLocal, arrayItemIndex); + } + // load name + if (name != null) + { + ilg.Load(name); + } + else + { + ilg.LoadArrayElement(memberNamesLocal, nameIndex); + } + // load namespace + ilg.Load(ns); + // call method to write primitive + ilg.Call(primitiveContract.XmlFormatWriterMethod); + return true; + } + + bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value, LocalBuilder itemName, LocalBuilder itemNamespace) + { + PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType); + if (primitiveContract == null) + return false; + + string writeArrayMethod = null; + switch (Type.GetTypeCode(itemType)) + { + case TypeCode.Boolean: + writeArrayMethod = "WriteBooleanArray"; + break; + case TypeCode.DateTime: + writeArrayMethod = "WriteDateTimeArray"; + break; + case TypeCode.Decimal: + writeArrayMethod = "WriteDecimalArray"; + break; + case TypeCode.Int32: + writeArrayMethod = "WriteInt32Array"; + break; + case TypeCode.Int64: + writeArrayMethod = "WriteInt64Array"; + break; + case TypeCode.Single: + writeArrayMethod = "WriteSingleArray"; + break; + case TypeCode.Double: + writeArrayMethod = "WriteDoubleArray"; + break; + default: + break; + } + if (writeArrayMethod != null) + { + ilg.Load(xmlWriterArg); + ilg.Load(value); + ilg.Load(itemName); + ilg.Load(itemNamespace); + ilg.Call(typeof(XmlWriterDelegator).GetMethod(writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null)); + return true; + } + return false; + } + + void WriteValue(LocalBuilder memberValue, bool writeXsiType) + { + Type memberType = memberValue.LocalType; + if (memberType.IsPointer) + { + ilg.Load(memberValue); + ilg.Load(memberType); + ilg.Call(XmlFormatGeneratorStatics.BoxPointer); + memberType = Globals.TypeOfReflectionPointer; + memberValue = ilg.DeclareLocal(memberType, "memberValueRefPointer"); + ilg.Store(memberValue); + } + bool isNullableOfT = (memberType.IsGenericType && + memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable); + if (memberType.IsValueType && !isNullableOfT) + { + PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType); + if (primitiveContract != null && !writeXsiType) + ilg.Call(xmlWriterArg, primitiveContract.XmlFormatContentWriterMethod, memberValue); + else + InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, memberValue, memberType, writeXsiType); + } + else + { + if (isNullableOfT) + { + memberValue = UnwrapNullableObject(memberValue); //Leaves !HasValue on stack + memberType = memberValue.LocalType; + } + else + { + ilg.Load(memberValue); + ilg.Load(null); + ilg.Ceq(); + } + ilg.If(); + ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteNullMethod, xmlWriterArg, memberType, DataContract.IsTypeSerializable(memberType)); + ilg.Else(); + PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType); + if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType) + { + if (isNullableOfT) + { + ilg.Call(xmlWriterArg, primitiveContract.XmlFormatContentWriterMethod, memberValue); + } + else + { + ilg.Call(contextArg, primitiveContract.XmlFormatContentWriterMethod, xmlWriterArg, memberValue); + } + } + else + { + if (memberType == Globals.TypeOfObject || //boxed Nullable + memberType == Globals.TypeOfValueType || + ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType)) + { + ilg.Load(memberValue); + ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject); + memberValue = ilg.DeclareLocal(Globals.TypeOfObject, "unwrappedMemberValue"); + memberType = memberValue.LocalType; + ilg.Stloc(memberValue); + ilg.If(memberValue, Cmp.EqualTo, null); + ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteNullMethod, xmlWriterArg, memberType, DataContract.IsTypeSerializable(memberType)); + ilg.Else(); + } + InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod), + memberValue, memberType, writeXsiType); + + if (memberType == Globals.TypeOfObject) //boxed Nullable + ilg.EndIf(); + } + ilg.EndIf(); + } + } + + void InternalSerialize(MethodInfo methodInfo, LocalBuilder memberValue, Type memberType, bool writeXsiType) + { + ilg.Load(contextArg); + ilg.Load(xmlWriterArg); + ilg.Load(memberValue); + ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject); + LocalBuilder typeHandleValue = ilg.DeclareLocal(typeof(RuntimeTypeHandle), "typeHandleValue"); + ilg.Call(null, typeof(Type).GetMethod("GetTypeHandle"), memberValue); + ilg.Stloc(typeHandleValue); + ilg.LoadAddress(typeHandleValue); + ilg.Ldtoken(memberType); + ilg.Call(typeof(RuntimeTypeHandle).GetMethod("Equals", new Type[] { typeof(RuntimeTypeHandle) })); + ilg.Load(writeXsiType); + ilg.Load(DataContract.GetId(memberType.TypeHandle)); + ilg.Ldtoken(memberType); + ilg.Call(methodInfo); + } + + + LocalBuilder UnwrapNullableObject(LocalBuilder memberValue)// Leaves !HasValue on stack + { + Type memberType = memberValue.LocalType; + Label onNull = ilg.DefineLabel(); + Label end = ilg.DefineLabel(); + ilg.Load(memberValue); + while (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable) + { + Type innerType = memberType.GetGenericArguments()[0]; + ilg.Dup(); + ilg.Call(XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod(innerType)); + ilg.Brfalse(onNull); + ilg.Call(XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod(innerType)); + memberType = innerType; + } + memberValue = ilg.DeclareLocal(memberType, "nullableUnwrappedMemberValue"); + ilg.Stloc(memberValue); + ilg.Load(false); //isNull + ilg.Br(end); + ilg.MarkLabel(onNull); + ilg.Pop(); + ilg.Call(XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod(memberType)); + ilg.Stloc(memberValue); + ilg.Load(true); //isNull + ilg.MarkLabel(end); + return memberValue; + } + + bool NeedsPrefix(Type type, XmlDictionaryString ns) + { + return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0); + } + + void WriteStartElement(Type type, XmlDictionaryString ns, LocalBuilder namespaceLocal, LocalBuilder nameLocal, int nameIndex) + { + bool needsPrefix = NeedsPrefix(type, ns); + ilg.Load(xmlWriterArg); + // prefix + if (needsPrefix) + ilg.Load(Globals.ElementPrefix); + + // localName + if (nameLocal == null) + ilg.LoadArrayElement(memberNamesLocal, nameIndex); + else + ilg.Load(nameLocal); + + // namespace + ilg.Load(namespaceLocal); + + ilg.Call(needsPrefix ? XmlFormatGeneratorStatics.WriteStartElementMethod3 : XmlFormatGeneratorStatics.WriteStartElementMethod2); + } + + void WriteEndElement() + { + ilg.Call(xmlWriterArg, XmlFormatGeneratorStatics.WriteEndElementMethod); + } + + bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract) + { + // Check for conflict with base type members + if (CheckIfConflictingMembersHaveDifferentTypes(member)) + return true; + + // Check for conflict with derived type members + string name = member.Name; + string ns = classContract.StableName.Namespace; + ClassDataContract currentContract = derivedMostClassContract; + while (currentContract != null && currentContract != classContract) + { + if (ns == currentContract.StableName.Namespace) + { + List members = currentContract.Members; + for (int j = 0; j < members.Count; j++) + { + if (name == members[j].Name) + return CheckIfConflictingMembersHaveDifferentTypes(members[j]); + } + } + currentContract = currentContract.BaseContract; + } + + return false; + } + + bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member) + { + while (member.ConflictingMember != null) + { + if (member.MemberType != member.ConflictingMember.MemberType) + return true; + member = member.ConflictingMember; + } + return false; + } + +#if NotUsed + static Hashtable nsToPrefixTable = new Hashtable(4); + internal static string GetPrefix(string ns) + { + string prefix = (string)nsToPrefixTable[ns]; + if (prefix == null) + { + lock (nsToPrefixTable) + { + if (prefix == null) + { + prefix = "p" + nsToPrefixTable.Count; + nsToPrefixTable.Add(ns, prefix); + } + } + } + return prefix; + } +#endif + + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializer.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializer.cs new file mode 100644 index 0000000..ac5930d --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializer.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text; +using System.Xml; +using DataContractResolver = System.Runtime.Serialization.DataContractResolver; +using FormatterConverter = System.Runtime.Serialization.FormatterConverter; +using IFormatterConverter = System.Runtime.Serialization.IFormatterConverter; +using SerializationException = System.Runtime.Serialization.SerializationException; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + public abstract class XmlObjectSerializer + { + public abstract void WriteStartObject(XmlDictionaryWriter writer, object graph); + public abstract void WriteObjectContent(XmlDictionaryWriter writer, object graph); + public abstract void WriteEndObject(XmlDictionaryWriter writer); + + public virtual void WriteObject(Stream stream, object graph) + { + stream = stream ?? throw new ArgumentNullException(nameof(stream)); + XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream: stream, encoding: Encoding.UTF8, ownsStream: false); + WriteObject(writer, graph); + writer.Flush(); + } + + public virtual void WriteObject(XmlWriter writer, object graph) + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + WriteObject(XmlDictionaryWriter.CreateDictionaryWriter(writer), graph); + } + + public virtual void WriteStartObject(XmlWriter writer, object graph) + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + WriteStartObject(XmlDictionaryWriter.CreateDictionaryWriter(writer), graph); + } + + public virtual void WriteObjectContent(XmlWriter writer, object graph) + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + WriteObjectContent(XmlDictionaryWriter.CreateDictionaryWriter(writer), graph); + } + + public virtual void WriteEndObject(XmlWriter writer) + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + WriteEndObject(XmlDictionaryWriter.CreateDictionaryWriter(writer)); + } + + public virtual void WriteObject(XmlDictionaryWriter writer, object graph) + { + WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph); + } + + internal void WriteObjectHandleExceptions(XmlWriterDelegator writer, object graph) + { + WriteObjectHandleExceptions(writer, graph, null); + } + + internal void WriteObjectHandleExceptions(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver) + { + try + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + InternalWriteObject(writer, graph, dataContractResolver); + } + catch (XmlException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex)); + } + catch (FormatException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex)); + } + } + + internal virtual DataContractDictionary KnownDataContracts => null; + + internal virtual void InternalWriteObject(XmlWriterDelegator writer, object graph) + { + WriteStartObject(writer.Writer, graph); + WriteObjectContent(writer.Writer, graph); + WriteEndObject(writer.Writer); + } + + internal virtual void InternalWriteObject(XmlWriterDelegator writer, object graph, DataContractResolver dataContractResolver) + { + InternalWriteObject(writer, graph); + } + + internal virtual void InternalWriteStartObject(XmlWriterDelegator writer, object graph) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); + } + internal virtual void InternalWriteObjectContent(XmlWriterDelegator writer, object graph) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); + } + internal virtual void InternalWriteEndObject(XmlWriterDelegator writer) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); + } + + internal void WriteStartObjectHandleExceptions(XmlWriterDelegator writer, object graph) + { + try + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + InternalWriteStartObject(writer, graph); + } + catch (XmlException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteStartObject, GetSerializeType(graph), ex), ex)); + } + catch (FormatException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteStartObject, GetSerializeType(graph), ex), ex)); + } + } + + internal void WriteObjectContentHandleExceptions(XmlWriterDelegator writer, object graph) + { + try + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + if (writer.WriteState != WriteState.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.XmlWriterMustBeInElement, writer.WriteState))); + } + InternalWriteObjectContent(writer, graph); + } + catch (XmlException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex)); + } + catch (FormatException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorSerializing, GetSerializeType(graph), ex), ex)); + } + } + + internal void WriteEndObjectHandleExceptions(XmlWriterDelegator writer) + { + try + { + writer = writer ?? throw new ArgumentNullException(nameof(writer)); + InternalWriteEndObject(writer); + } + catch (XmlException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteEndObject, null, ex), ex)); + } + catch (FormatException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorWriteEndObject, null, ex), ex)); + } + } + + internal void WriteRootElement(XmlWriterDelegator writer, DataContract contract, XmlDictionaryString name, XmlDictionaryString ns, bool needsContractNsAtRoot) + { + if (name == null) // root name not set explicitly + { + if (!contract.HasRoot) + { + return; + } + + contract.WriteRootElement(writer, contract.TopLevelElementName, contract.TopLevelElementNamespace); + } + else + { + contract.WriteRootElement(writer, name, ns); + if (needsContractNsAtRoot) + { + writer.WriteNamespaceDecl(contract.Namespace); + } + } + } + + internal bool CheckIfNeedsContractNsAtRoot(XmlDictionaryString name, XmlDictionaryString ns, DataContract contract) + { + if (name == null) + { + return false; + } + + if (contract.IsBuiltInDataContract || !contract.CanContainReferences || contract.IsISerializable) + { + return false; + } + + string contractNs = contract.Namespace?.Value; + if (string.IsNullOrEmpty(contractNs) || contractNs == ns?.Value) + { + return false; + } + + return true; + } + + internal static void WriteNull(XmlWriterDelegator writer) + { + writer.WriteAttributeBool(Globals.XsiPrefix, DictionaryGlobals.XsiNilLocalName, DictionaryGlobals.SchemaInstanceNamespace, true); + } + + internal static bool IsContractDeclared(DataContract contract, DataContract declaredContract) + { + return (object.ReferenceEquals(contract.Name, declaredContract.Name) && object.ReferenceEquals(contract.Namespace, declaredContract.Namespace)) + || (contract.Name.Value == declaredContract.Name.Value && contract.Namespace.Value == declaredContract.Namespace.Value); + } + + public virtual object ReadObject(Stream stream) + { + stream = stream ?? throw new ArgumentNullException(nameof(stream)); + return ReadObject(XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max)); + } + + public virtual object ReadObject(XmlReader reader) + { + reader = reader ?? throw new ArgumentNullException(nameof(reader)); + return ReadObject(XmlDictionaryReader.CreateDictionaryReader(reader)); + } + + public virtual object ReadObject(XmlDictionaryReader reader) + { + return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/); + } + + public virtual object ReadObject(XmlReader reader, bool verifyObjectName) + { + reader = reader ?? throw new ArgumentNullException(nameof(reader)); + return ReadObject(XmlDictionaryReader.CreateDictionaryReader(reader), verifyObjectName); + } + + public abstract object ReadObject(XmlDictionaryReader reader, bool verifyObjectName); + + public virtual bool IsStartObject(XmlReader reader) + { + reader = reader ?? throw new ArgumentNullException(nameof(reader)); + return IsStartObject(XmlDictionaryReader.CreateDictionaryReader(reader)); + } + + public abstract bool IsStartObject(XmlDictionaryReader reader); + + internal virtual object InternalReadObject(XmlReaderDelegator reader, bool verifyObjectName) + { + return ReadObject(reader.UnderlyingReader, verifyObjectName); + } + + internal virtual object InternalReadObject(XmlReaderDelegator reader, bool verifyObjectName, DataContractResolver dataContractResolver) + { + return InternalReadObject(reader, verifyObjectName); + } + + internal virtual bool InternalIsStartObject(XmlReaderDelegator reader) + { + Fx.Assert("XmlObjectSerializer.InternalIsStartObject should never get called"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); + } + + internal object ReadObjectHandleExceptions(XmlReaderDelegator reader, bool verifyObjectName) + { + return ReadObjectHandleExceptions(reader, verifyObjectName, null); + } + + internal object ReadObjectHandleExceptions(XmlReaderDelegator reader, bool verifyObjectName, DataContractResolver dataContractResolver) + { + try + { + reader = reader ?? throw new ArgumentNullException(nameof(reader)); + return InternalReadObject(reader, verifyObjectName, dataContractResolver); + } + catch (XmlException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorDeserializing, GetDeserializeType(), ex), ex)); + } + catch (FormatException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorDeserializing, GetDeserializeType(), ex), ex)); + } + } + + internal bool IsStartObjectHandleExceptions(XmlReaderDelegator reader) + { + try + { + reader = reader ?? throw new ArgumentNullException(nameof(reader)); + return InternalIsStartObject(reader); + } + catch (XmlException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorIsStartObject, GetDeserializeType(), ex), ex)); + } + catch (FormatException ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(GetTypeInfoError(SR.ErrorIsStartObject, GetDeserializeType(), ex), ex)); + } + } + + internal bool IsRootXmlAny(XmlDictionaryString rootName, DataContract contract) + { + return (rootName == null) && !contract.HasRoot; + } + + internal bool IsStartElement(XmlReaderDelegator reader) + { + return (reader.MoveToElement() || reader.IsStartElement()); + } + + internal bool IsRootElement(XmlReaderDelegator reader, DataContract contract, XmlDictionaryString name, XmlDictionaryString ns) + { + reader.MoveToElement(); + if (name != null) // root name set explicitly + { + return reader.IsStartElement(name, ns); + } + else + { + if (!contract.HasRoot) + { + return reader.IsStartElement(); + } + + if (reader.IsStartElement(contract.TopLevelElementName, contract.TopLevelElementNamespace)) + { + return true; + } + + ClassDataContract classContract = contract as ClassDataContract; + if (classContract != null) + { + classContract = classContract.BaseContract; + } + + while (classContract != null) + { + if (reader.IsStartElement(classContract.TopLevelElementName, classContract.TopLevelElementNamespace)) + { + return true; + } + + classContract = classContract.BaseContract; + } + if (classContract == null) + { + DataContract objectContract = PrimitiveDataContract.GetPrimitiveDataContract(Globals.TypeOfObject); + if (reader.IsStartElement(objectContract.TopLevelElementName, objectContract.TopLevelElementNamespace)) + { + return true; + } + } + return false; + } + } + + internal static string TryAddLineInfo(XmlReaderDelegator reader, string errorMessage) + { + if (reader.HasLineInfo()) + { + return string.Format(CultureInfo.InvariantCulture, "{0} {1}", SR.Format(SR.ErrorInLine, reader.LineNumber, reader.LinePosition), errorMessage); + } + + return errorMessage; + } + + internal static Exception CreateSerializationExceptionWithReaderDetails(string errorMessage, XmlReaderDelegator reader) + { + return XmlObjectSerializer.CreateSerializationException(TryAddLineInfo(reader, SR.Format(SR.EncounteredWithNameNamespace, errorMessage, reader.NodeType, reader.LocalName, reader.NamespaceURI))); + } + + internal static SerializationException CreateSerializationException(string errorMessage) + { + return XmlObjectSerializer.CreateSerializationException(errorMessage, null); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static SerializationException CreateSerializationException(string errorMessage, Exception innerException) + { + return new SerializationException(errorMessage, innerException); + } + + private static string GetTypeInfoError(string errorMessage, Type type, Exception innerException) + { + string typeInfo = (type == null) ? string.Empty : SR.Format(SR.ErrorTypeInfo, DataContract.GetClrTypeFullName(type)); + string innerExceptionMessage = innerException?.Message ?? string.Empty; + return SR.Format(errorMessage, typeInfo, innerExceptionMessage); + } + + internal virtual Type GetSerializeType(object graph) + { + return graph?.GetType(); + } + + internal virtual Type GetDeserializeType() + { + return null; + } + + private static IFormatterConverter formatterConverter; + internal static IFormatterConverter FormatterConverter + { + get + { + if (formatterConverter == null) + { + formatterConverter = new FormatterConverter(); + } + + return formatterConverter; + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerContext.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerContext.cs new file mode 100644 index 0000000..237e6c3 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -0,0 +1,342 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Security; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + using DataContractDictionary = Dictionary; + + internal class XmlObjectSerializerContext + { + + protected XmlObjectSerializer serializer; + protected DataContract rootTypeDataContract; + internal ScopedKnownTypes scopedKnownTypes = new ScopedKnownTypes(); + protected DataContractDictionary serializerKnownDataContracts; + private bool isSerializerKnownDataContractsSetExplicit; + protected IList serializerKnownTypeList; + + private int itemCount; + private readonly int maxItemsInObjectGraph; + private System.Runtime.Serialization.StreamingContext streamingContext; + private readonly bool ignoreExtensionDataObject; + private readonly System.Runtime.Serialization.DataContractResolver dataContractResolver; + private KnownTypeDataContractResolver knownTypeResolver; + + internal XmlObjectSerializerContext( + XmlObjectSerializer serializer, + int maxItemsInObjectGraph, + System.Runtime.Serialization.StreamingContext streamingContext, + bool ignoreExtensionDataObject, + System.Runtime.Serialization.DataContractResolver dataContractResolver) + { + this.serializer = serializer; + itemCount = 1; + this.maxItemsInObjectGraph = maxItemsInObjectGraph; + this.streamingContext = streamingContext; + this.ignoreExtensionDataObject = ignoreExtensionDataObject; + this.dataContractResolver = dataContractResolver; + } + + internal XmlObjectSerializerContext(XmlObjectSerializer serializer, + int maxItemsInObjectGraph, + System.Runtime.Serialization.StreamingContext streamingContext, + bool ignoreExtensionDataObject) + : this(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject, null) + { + } + + internal XmlObjectSerializerContext( + DataContractSerializer serializer, + DataContract rootTypeDataContract, + System.Runtime.Serialization.DataContractResolver dataContractResolver) + : this(serializer, + serializer.MaxItemsInObjectGraph, + new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.All), + serializer.IgnoreExtensionDataObject, + dataContractResolver) + { + this.rootTypeDataContract = rootTypeDataContract; + serializerKnownTypeList = serializer.knownTypeList; + } + + internal XmlObjectSerializerContext(NetDataContractSerializer serializer) + : this(serializer, + serializer.MaxItemsInObjectGraph, + serializer.Context, + serializer.IgnoreExtensionDataObject) + { + } + + internal virtual SerializationMode Mode => SerializationMode.SharedContract; + + internal virtual bool IsGetOnlyCollection + { + get => false; + set { } + } + + public System.Runtime.Serialization.StreamingContext GetStreamingContext() + { + return streamingContext; + } + + private static MethodInfo incrementItemCountMethod; + internal static MethodInfo IncrementItemCountMethod + { + get + { + if (incrementItemCountMethod == null) + { + incrementItemCountMethod = typeof(XmlObjectSerializerContext).GetMethod("IncrementItemCount", Globals.ScanAllMembers); + } + + return incrementItemCountMethod; + } + } + public void IncrementItemCount(int count) + { + if (count > maxItemsInObjectGraph - itemCount) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExceededMaxItemsQuota, maxItemsInObjectGraph))); + } + + itemCount += count; + } + + internal int RemainingItemCount => maxItemsInObjectGraph - itemCount; + + internal bool IgnoreExtensionDataObject => ignoreExtensionDataObject; + + protected System.Runtime.Serialization.DataContractResolver DataContractResolver => dataContractResolver; + + protected KnownTypeDataContractResolver KnownTypeResolver + { + get + { + if (knownTypeResolver == null) + { + knownTypeResolver = new KnownTypeDataContractResolver(this); + } + return knownTypeResolver; + } + } + + internal DataContract GetDataContract(Type type) + { + return GetDataContract(type.TypeHandle, type); + } + + internal virtual DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type) + { + if (IsGetOnlyCollection) + { + return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(typeHandle), typeHandle, type, Mode); + } + else + { + return DataContract.GetDataContract(typeHandle, type, Mode); + } + } + + internal virtual DataContract GetDataContractSkipValidation(int typeId, RuntimeTypeHandle typeHandle, Type type) + { + if (IsGetOnlyCollection) + { + return DataContract.GetGetOnlyCollectionDataContractSkipValidation(typeId, typeHandle, type); + } + else + { + return DataContract.GetDataContractSkipValidation(typeId, typeHandle, type); + } + } + + + internal virtual DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle) + { + if (IsGetOnlyCollection) + { + return DataContract.GetGetOnlyCollectionDataContract(id, typeHandle, null /*type*/, Mode); + } + else + { + return DataContract.GetDataContract(id, typeHandle, Mode); + } + } + + internal virtual void CheckIfTypeSerializable(Type memberType, bool isMemberTypeSerializable) + { + if (!isMemberTypeSerializable) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.TypeNotSerializable, memberType))); + } + } + + internal virtual Type GetSurrogatedType(Type type) + { + return type; + } + + private DataContractDictionary SerializerKnownDataContracts + { + get + { + // This field must be initialized during construction by serializers using data contracts. + if (!isSerializerKnownDataContractsSetExplicit) + { + serializerKnownDataContracts = serializer.KnownDataContracts; + isSerializerKnownDataContractsSetExplicit = true; + } + return serializerKnownDataContracts; + } + } + + private DataContract GetDataContractFromSerializerKnownTypes(XmlQualifiedName qname) + { + DataContractDictionary serializerKnownDataContracts = SerializerKnownDataContracts; + if (serializerKnownDataContracts == null) + { + return null; + } + + return serializerKnownDataContracts.TryGetValue(qname, out DataContract outDataContract) ? outDataContract : null; + } + + internal static DataContractDictionary GetDataContractsForKnownTypes(IList knownTypeList) + { + if (knownTypeList == null) + { + return null; + } + + DataContractDictionary dataContracts = new DataContractDictionary(); + Dictionary typesChecked = new Dictionary(); + for (int i = 0; i < knownTypeList.Count; i++) + { + Type knownType = knownTypeList[i]; + if (knownType == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.NullKnownType, "knownTypes"))); + } + + DataContract.CheckAndAdd(knownType, typesChecked, ref dataContracts); + } + return dataContracts; + } + + internal bool IsKnownType(DataContract dataContract, DataContractDictionary knownDataContracts, Type declaredType) + { + bool knownTypesAddedInCurrentScope = false; + if (knownDataContracts != null) + { + scopedKnownTypes.Push(knownDataContracts); + knownTypesAddedInCurrentScope = true; + } + + bool isKnownType = IsKnownType(dataContract, declaredType); + + if (knownTypesAddedInCurrentScope) + { + scopedKnownTypes.Pop(); + } + return isKnownType; + } + + internal bool IsKnownType(DataContract dataContract, Type declaredType) + { + DataContract knownContract = ResolveDataContractFromKnownTypes(dataContract.StableName.Name, dataContract.StableName.Namespace, null /*memberTypeContract*/, declaredType); + return knownContract != null && knownContract.UnderlyingType == dataContract.UnderlyingType; + } + + private DataContract ResolveDataContractFromKnownTypes(XmlQualifiedName typeName) + { + DataContract dataContract = PrimitiveDataContract.GetPrimitiveDataContract(typeName.Name, typeName.Namespace); + if (dataContract == null) + { + dataContract = scopedKnownTypes.GetDataContract(typeName); + if (dataContract == null) + { + dataContract = GetDataContractFromSerializerKnownTypes(typeName); + } + } + return dataContract; + } + + private DataContract ResolveDataContractFromDataContractResolver(XmlQualifiedName typeName, Type declaredType) + { + Type dataContractType = DataContractResolver.ResolveName(typeName.Name, typeName.Namespace, declaredType, KnownTypeResolver); + if (dataContractType == null) + { + return null; + } + else + { + return GetDataContract(dataContractType); + } + } + + internal Type ResolveNameFromKnownTypes(XmlQualifiedName typeName) + { + DataContract dataContract = ResolveDataContractFromKnownTypes(typeName); + if (dataContract == null) + { + return null; + } + else + { + return dataContract.OriginalUnderlyingType; + } + } + + protected DataContract ResolveDataContractFromKnownTypes(string typeName, string typeNs, DataContract memberTypeContract, Type declaredType) + { + XmlQualifiedName qname = new XmlQualifiedName(typeName, typeNs); + DataContract dataContract; + if (DataContractResolver == null) + { + dataContract = ResolveDataContractFromKnownTypes(qname); + } + else + { + dataContract = ResolveDataContractFromDataContractResolver(qname, declaredType); + } + if (dataContract == null) + { + if (memberTypeContract != null + && !memberTypeContract.UnderlyingType.IsInterface + && memberTypeContract.StableName == qname) + { + dataContract = memberTypeContract; + } + if (dataContract == null && rootTypeDataContract != null) + { + dataContract = ResolveDataContractFromRootDataContract(qname); + } + } + return dataContract; + } + + protected virtual DataContract ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName) + { + if (rootTypeDataContract.StableName == typeQName) + { + return rootTypeDataContract; + } + + CollectionDataContract collectionContract = rootTypeDataContract as CollectionDataContract; + while (collectionContract != null) + { + DataContract itemContract = GetDataContract(GetSurrogatedType(collectionContract.ItemType)); + if (itemContract.StableName == typeQName) + { + return itemContract; + } + collectionContract = itemContract as CollectionDataContract; + } + return null; + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContext.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContext.cs new file mode 100644 index 0000000..8dfd2ea --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContext.cs @@ -0,0 +1,1225 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace Compat.Runtime.Serialization +{ + internal class XmlObjectSerializerReadContext : XmlObjectSerializerContext + { + internal Attributes attributes; + private HybridObjectCache deserializedObjects; + private XmlSerializableReader xmlSerializableReader; + private XmlDocument xmlDocument; + private Attributes attributesInXmlData; + private XmlReaderDelegator extensionDataReader; + private object getOnlyCollectionValue; + private bool isGetOnlyCollection; + + private HybridObjectCache DeserializedObjects + { + get + { + if (deserializedObjects == null) + { + deserializedObjects = new HybridObjectCache(); + } + + return deserializedObjects; + } + } + + private XmlDocument Document + { + get + { + if (xmlDocument == null) + { + xmlDocument = new XmlDocument(); + } + + return xmlDocument; + } + } + + internal override bool IsGetOnlyCollection + { + get => isGetOnlyCollection; + set => isGetOnlyCollection = value; + } + + + internal object GetCollectionMember() + { + return getOnlyCollectionValue; + } + + internal void StoreCollectionMemberInfo(object collectionMember) + { + getOnlyCollectionValue = collectionMember; + isGetOnlyCollection = true; + } + + internal static void ThrowNullValueReturnedForGetOnlyCollectionException(Type type) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NullValueReturnedForGetOnlyCollection, DataContract.GetClrTypeFullName(type)))); + } + + internal static void ThrowArrayExceededSizeException(int arraySize, Type type) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayExceededSize, arraySize, DataContract.GetClrTypeFullName(type)))); + } + + internal static XmlObjectSerializerReadContext CreateContext( + DataContractSerializer serializer, + DataContract rootTypeDataContract, + System.Runtime.Serialization.DataContractResolver dataContractResolver) + { + return (serializer.PreserveObjectReferences || serializer.DataContractSurrogate != null) + ? new XmlObjectSerializerReadContextComplex(serializer, rootTypeDataContract, dataContractResolver) + : new XmlObjectSerializerReadContext(serializer, rootTypeDataContract, dataContractResolver); + } + + internal static XmlObjectSerializerReadContext CreateContext(NetDataContractSerializer serializer) + { + return new XmlObjectSerializerReadContextComplex(serializer); + } + + internal XmlObjectSerializerReadContext( + XmlObjectSerializer serializer, + int maxItemsInObjectGraph, + System.Runtime.Serialization.StreamingContext streamingContext, + bool ignoreExtensionDataObject) + : base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject) + { + } + + internal XmlObjectSerializerReadContext( + DataContractSerializer serializer, + DataContract rootTypeDataContract, + System.Runtime.Serialization.DataContractResolver dataContractResolver) + : base(serializer, rootTypeDataContract, dataContractResolver) + { + attributes = new Attributes(); + } + + protected XmlObjectSerializerReadContext(NetDataContractSerializer serializer) + : base(serializer) + { + attributes = new Attributes(); + } + + public virtual object InternalDeserialize(XmlReaderDelegator xmlReader, int id, RuntimeTypeHandle declaredTypeHandle, string name, string ns) + { + DataContract dataContract = GetDataContract(id, declaredTypeHandle); + return InternalDeserialize(xmlReader, name, ns, Type.GetTypeFromHandle(declaredTypeHandle), ref dataContract); + } + + internal virtual object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string name, string ns) + { + DataContract dataContract = GetDataContract(declaredType); + return InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract); + } + + internal virtual object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, string name, string ns) + { + if (dataContract == null) + { + GetDataContract(declaredType); + } + + return InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract); + } + + protected bool TryHandleNullOrRef(XmlReaderDelegator reader, Type declaredType, string name, string ns, ref object retObj) + { + ReadAttributes(reader); + + if (attributes.Ref != Globals.NewObjectId) + { + if (isGetOnlyCollection) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IsReferenceGetOnlyCollectionsNotSupported, attributes.Ref, DataContract.GetClrTypeFullName(declaredType)))); + } + else + { + retObj = GetExistingObject(attributes.Ref, declaredType, name, ns); + reader.Skip(); + return true; + } + } + else if (attributes.XsiNil) + { + reader.Skip(); + return true; + } + return false; + } + + protected object InternalDeserialize(XmlReaderDelegator reader, string name, string ns, Type declaredType, ref DataContract dataContract) + { + object retObj = null; + if (TryHandleNullOrRef(reader, dataContract.UnderlyingType, name, ns, ref retObj)) + { + return retObj; + } + + bool knownTypesAddedInCurrentScope = false; + if (dataContract.KnownDataContracts != null) + { + scopedKnownTypes.Push(dataContract.KnownDataContracts); + knownTypesAddedInCurrentScope = true; + } + + if (attributes.XsiTypeName != null) + { + dataContract = ResolveDataContractFromKnownTypes(attributes.XsiTypeName, attributes.XsiTypeNamespace, dataContract, declaredType); + if (dataContract == null) + { + if (DataContractResolver == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(reader, SR.Format(SR.DcTypeNotFoundOnDeserialize, attributes.XsiTypeNamespace, attributes.XsiTypeName, reader.NamespaceURI, reader.LocalName)))); + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(reader, SR.Format(SR.DcTypeNotResolvedOnDeserialize, attributes.XsiTypeNamespace, attributes.XsiTypeName, reader.NamespaceURI, reader.LocalName)))); + } + knownTypesAddedInCurrentScope = ReplaceScopedKnownTypesTop(dataContract.KnownDataContracts, knownTypesAddedInCurrentScope); + } + + if (dataContract.IsISerializable && attributes.FactoryTypeName != null) + { + DataContract factoryDataContract = ResolveDataContractFromKnownTypes(attributes.FactoryTypeName, attributes.FactoryTypeNamespace, dataContract, declaredType); + if (factoryDataContract != null) + { + if (factoryDataContract.IsISerializable) + { + dataContract = factoryDataContract; + knownTypesAddedInCurrentScope = ReplaceScopedKnownTypesTop(dataContract.KnownDataContracts, knownTypesAddedInCurrentScope); + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.FactoryTypeNotISerializable, DataContract.GetClrTypeFullName(factoryDataContract.UnderlyingType), DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + } + } + + if (knownTypesAddedInCurrentScope) + { + object obj = ReadDataContractValue(dataContract, reader); + scopedKnownTypes.Pop(); + return obj; + } + else + { + return ReadDataContractValue(dataContract, reader); + } + } + + private bool ReplaceScopedKnownTypesTop(Dictionary knownDataContracts, bool knownTypesAddedInCurrentScope) + { + if (knownTypesAddedInCurrentScope) + { + scopedKnownTypes.Pop(); + knownTypesAddedInCurrentScope = false; + } + if (knownDataContracts != null) + { + scopedKnownTypes.Push(knownDataContracts); + knownTypesAddedInCurrentScope = true; + } + return knownTypesAddedInCurrentScope; + } + + public static bool MoveToNextElement(XmlReaderDelegator xmlReader) + { + return (xmlReader.MoveToContent() != XmlNodeType.EndElement); + } + + public int GetMemberIndex( + XmlReaderDelegator xmlReader, + XmlDictionaryString[] memberNames, + XmlDictionaryString[] memberNamespaces, + int memberIndex, + ExtensionDataObject extensionData) + { + for (int i = memberIndex + 1; i < memberNames.Length; i++) + { + if (xmlReader.IsStartElement(memberNames[i], memberNamespaces[i])) + { + return i; + } + } + HandleMemberNotFound(xmlReader, extensionData, memberIndex); + return memberNames.Length; + } + + public int GetMemberIndexWithRequiredMembers( + XmlReaderDelegator xmlReader, + XmlDictionaryString[] memberNames, + XmlDictionaryString[] memberNamespaces, + int memberIndex, + int requiredIndex, + ExtensionDataObject extensionData) + { + for (int i = memberIndex + 1; i < memberNames.Length; i++) + { + if (xmlReader.IsStartElement(memberNames[i], memberNamespaces[i])) + { + if (requiredIndex < i) + { + ThrowRequiredMemberMissingException(xmlReader, memberIndex, requiredIndex, memberNames); + } + + return i; + } + } + HandleMemberNotFound(xmlReader, extensionData, memberIndex); + return memberNames.Length; + } + + public static void ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, int memberIndex, int requiredIndex, XmlDictionaryString[] memberNames) + { + StringBuilder stringBuilder = new StringBuilder(); + if (requiredIndex == memberNames.Length) + { + requiredIndex--; + } + + for (int i = memberIndex + 1; i <= requiredIndex; i++) + { + if (stringBuilder.Length != 0) + { + stringBuilder.Append(" | "); + } + + stringBuilder.Append(memberNames[i].Value); + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.UnexpectedElementExpectingElements, xmlReader.NodeType, xmlReader.LocalName, xmlReader.NamespaceURI, stringBuilder.ToString())))); + } + + protected void HandleMemberNotFound(XmlReaderDelegator xmlReader, ExtensionDataObject extensionData, int memberIndex) + { + xmlReader.MoveToContent(); + if (xmlReader.NodeType != XmlNodeType.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + if (IgnoreExtensionDataObject || extensionData == null) + { + SkipUnknownElement(xmlReader); + } + else + { + HandleUnknownElement(xmlReader, extensionData, memberIndex); + } + } + + internal void HandleUnknownElement(XmlReaderDelegator xmlReader, ExtensionDataObject extensionData, int memberIndex) + { + if (extensionData.Members == null) + { + extensionData.Members = new List(); + } + + extensionData.Members.Add(ReadExtensionDataMember(xmlReader, memberIndex)); + } + + public void SkipUnknownElement(XmlReaderDelegator xmlReader) + { + ReadAttributes(xmlReader); + xmlReader.Skip(); + } + + public string ReadIfNullOrRef(XmlReaderDelegator xmlReader, Type memberType, bool isMemberTypeSerializable) + { + if (attributes.Ref != Globals.NewObjectId) + { + CheckIfTypeSerializable(memberType, isMemberTypeSerializable); + xmlReader.Skip(); + return attributes.Ref; + } + else if (attributes.XsiNil) + { + CheckIfTypeSerializable(memberType, isMemberTypeSerializable); + xmlReader.Skip(); + return Globals.NullObjectId; + } + return Globals.NewObjectId; + } + + internal virtual void ReadAttributes(XmlReaderDelegator xmlReader) + { + if (attributes == null) + { + attributes = new Attributes(); + } + + attributes.Read(xmlReader); + } + + public void ResetAttributes() + { + if (attributes != null) + { + attributes.Reset(); + } + } + + public string GetObjectId() + { + return attributes.Id; + } + + internal virtual int GetArraySize() + { + return -1; + } + + public void AddNewObject(object obj) + { + AddNewObjectWithId(attributes.Id, obj); + } + + public void AddNewObjectWithId(string id, object obj) + { + if (id != Globals.NewObjectId) + { + DeserializedObjects.Add(id, obj); + } + + if (extensionDataReader != null) + { + extensionDataReader.UnderlyingExtensionDataReader.SetDeserializedValue(obj); + } + } + + public void ReplaceDeserializedObject(string id, object oldObj, object newObj) + { + if (object.ReferenceEquals(oldObj, newObj)) + { + return; + } + + if (id != Globals.NewObjectId) + { + // In certain cases (IObjectReference, SerializationSurrogate or DataContractSurrogate), + // an object can be replaced with a different object once it is deserialized. If the + // object happens to be referenced from within itself, that reference needs to be updated + // with the new instance. BinaryFormatter supports this by fixing up such references later. + // These XmlObjectSerializer implementations do not currently support fix-ups. Hence we + // throw in such cases to allow us add fix-up support in the future if we need to. + if (DeserializedObjects.IsObjectReferenced(id)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.FactoryObjectContainsSelfReference, DataContract.GetClrTypeFullName(oldObj.GetType()), DataContract.GetClrTypeFullName(newObj.GetType()), id))); + } + + DeserializedObjects.Remove(id); + DeserializedObjects.Add(id, newObj); + } + if (extensionDataReader != null) + { + extensionDataReader.UnderlyingExtensionDataReader.SetDeserializedValue(newObj); + } + } + + public object GetExistingObject(string id, Type type, string name, string ns) + { + object retObj = DeserializedObjects.GetObject(id); + if (retObj == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DeserializedObjectWithIdNotFound, id))); + } + + if (retObj is IDataNode) + { + IDataNode dataNode = (IDataNode)retObj; + retObj = (dataNode.Value != null && dataNode.IsFinalValue) ? dataNode.Value : DeserializeFromExtensionData(dataNode, type, name, ns); + } + return retObj; + } + + private object GetExistingObjectOrExtensionData(string id) + { + object retObj = DeserializedObjects.GetObject(id); + if (retObj == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DeserializedObjectWithIdNotFound, id))); + } + + return retObj; + } + + public object GetRealObject(System.Runtime.Serialization.IObjectReference obj, string id) + { + object realObj = SurrogateDataContract.GetRealObject(obj, GetStreamingContext()); + // If GetRealObject returns null, it indicates that the object could not resolve itself because + // it is missing information. This may occur in a case where multiple IObjectReference instances + // depend on each other. BinaryFormatter supports this by fixing up the references later. These + // XmlObjectSerializer implementations do not support fix-ups since the format does not contain + // forward references. However, we throw for this case since it allows us to add fix-up support + // in the future if we need to. + if (realObj == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.GetRealObjectReturnedNull, DataContract.GetClrTypeFullName(obj.GetType())))); + } + + ReplaceDeserializedObject(id, obj, realObj); + return realObj; + } + + private object DeserializeFromExtensionData(IDataNode dataNode, Type type, string name, string ns) + { + ExtensionDataReader underlyingExtensionDataReader; + if (extensionDataReader == null) + { + underlyingExtensionDataReader = new ExtensionDataReader(this); + extensionDataReader = CreateReaderDelegatorForReader(underlyingExtensionDataReader); + } + else + { + underlyingExtensionDataReader = extensionDataReader.UnderlyingExtensionDataReader; + } + + underlyingExtensionDataReader.SetDataNode(dataNode, name, ns); + object retObj = InternalDeserialize(extensionDataReader, type, name, ns); + dataNode.Clear(); + underlyingExtensionDataReader.Reset(); + return retObj; + } + + public static void Read(XmlReaderDelegator xmlReader) + { + if (!xmlReader.Read()) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.UnexpectedEndOfFile)); + } + } + + internal static void ParseQualifiedName(string qname, XmlReaderDelegator xmlReader, out string name, out string ns, out string prefix) + { + int colon = qname.IndexOf(':'); + prefix = ""; + if (colon >= 0) + { + prefix = qname.Substring(0, colon); + } + + name = qname.Substring(colon + 1); + ns = xmlReader.LookupNamespace(prefix); + } + + public static T[] EnsureArraySize(T[] array, int index) + { + if (array.Length <= index) + { + if (index == int.MaxValue) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + XmlObjectSerializer.CreateSerializationException( + SR.Format(SR.MaxArrayLengthExceeded, int.MaxValue, + DataContract.GetClrTypeFullName(typeof(T))))); + } + int newSize = (index < int.MaxValue / 2) ? index * 2 : int.MaxValue; + T[] newArray = new T[newSize]; + Array.Copy(array, 0, newArray, 0, array.Length); + array = newArray; + } + return array; + } + + public static T[] TrimArraySize(T[] array, int size) + { + if (size != array.Length) + { + T[] newArray = new T[size]; + Array.Copy(array, 0, newArray, 0, size); + array = newArray; + } + return array; + } + + public void CheckEndOfArray(XmlReaderDelegator xmlReader, int arraySize, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (xmlReader.NodeType == XmlNodeType.EndElement) + { + return; + } + + while (xmlReader.IsStartElement()) + { + if (xmlReader.IsStartElement(itemName, itemNamespace)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayExceededSizeAttribute, arraySize, itemName.Value, itemNamespace.Value))); + } + + SkipUnknownElement(xmlReader); + } + if (xmlReader.NodeType != XmlNodeType.EndElement) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.EndElement, xmlReader)); + } + } + + internal object ReadIXmlSerializable(XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, bool isMemberType) + { + if (xmlSerializableReader == null) + { + xmlSerializableReader = new XmlSerializableReader(); + } + + return ReadIXmlSerializable(xmlSerializableReader, xmlReader, xmlDataContract, isMemberType); + } + + internal static object ReadRootIXmlSerializable(XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, bool isMemberType) + { + return ReadIXmlSerializable(new XmlSerializableReader(), xmlReader, xmlDataContract, isMemberType); + } + + internal static object ReadIXmlSerializable(XmlSerializableReader xmlSerializableReader, XmlReaderDelegator xmlReader, XmlDataContract xmlDataContract, bool isMemberType) + { + object obj = null; + xmlSerializableReader.BeginRead(xmlReader); + if (isMemberType && !xmlDataContract.HasRoot) + { + xmlReader.Read(); + xmlReader.MoveToContent(); + } + if (xmlDataContract.UnderlyingType == Globals.TypeOfXmlElement) + { + if (!xmlReader.IsStartElement()) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + XmlDocument xmlDoc = new XmlDocument(); + obj = (XmlElement)xmlDoc.ReadNode(xmlSerializableReader); + } + else if (xmlDataContract.UnderlyingType == Globals.TypeOfXmlNodeArray) + { + obj = System.Runtime.Serialization.XmlSerializableServices.ReadNodes(xmlSerializableReader); + } + else + { + IXmlSerializable xmlSerializable = xmlDataContract.CreateXmlSerializableDelegate(); + xmlSerializable.ReadXml(xmlSerializableReader); + obj = xmlSerializable; + } + xmlSerializableReader.EndRead(); + return obj; + } + + public System.Runtime.Serialization.SerializationInfo ReadSerializationInfo(XmlReaderDelegator xmlReader, Type type) + { + System.Runtime.Serialization.SerializationInfo serInfo = new System.Runtime.Serialization.SerializationInfo(type, XmlObjectSerializer.FormatterConverter); + XmlNodeType nodeType; + while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement) + { + if (nodeType != XmlNodeType.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + if (xmlReader.NamespaceURI.Length != 0) + { + SkipUnknownElement(xmlReader); + continue; + } + string name = XmlConvert.DecodeName(xmlReader.LocalName); + + IncrementItemCount(1); + ReadAttributes(xmlReader); + object value; + if (attributes.Ref != Globals.NewObjectId) + { + xmlReader.Skip(); + value = GetExistingObject(attributes.Ref, null, name, string.Empty); + } + else if (attributes.XsiNil) + { + xmlReader.Skip(); + value = null; + } + else + { + value = InternalDeserialize(xmlReader, Globals.TypeOfObject, name, string.Empty); + } + + serInfo.AddValue(name, value); + } + + return serInfo; + } + + protected virtual DataContract ResolveDataContractFromTypeName() + { + return (attributes.XsiTypeName == null) ? null : ResolveDataContractFromKnownTypes(attributes.XsiTypeName, attributes.XsiTypeNamespace, null /*memberTypeContract*/, null); + } + + private ExtensionDataMember ReadExtensionDataMember(XmlReaderDelegator xmlReader, int memberIndex) + { + ExtensionDataMember member = new ExtensionDataMember + { + Name = xmlReader.LocalName, + Namespace = xmlReader.NamespaceURI, + MemberIndex = memberIndex + }; + if (xmlReader.UnderlyingExtensionDataReader != null) + { + // no need to re-read extension data structure + member.Value = xmlReader.UnderlyingExtensionDataReader.GetCurrentNode(); + } + else + { + member.Value = ReadExtensionDataValue(xmlReader); + } + + return member; + } + + public IDataNode ReadExtensionDataValue(XmlReaderDelegator xmlReader) + { + ReadAttributes(xmlReader); + IncrementItemCount(1); + IDataNode dataNode = null; + if (attributes.Ref != Globals.NewObjectId) + { + xmlReader.Skip(); + object o = GetExistingObjectOrExtensionData(attributes.Ref); + dataNode = (o is IDataNode) ? (IDataNode)o : new DataNode(o); + dataNode.Id = attributes.Ref; + } + else if (attributes.XsiNil) + { + xmlReader.Skip(); + dataNode = null; + } + else + { + string dataContractName = null; + string dataContractNamespace = null; + if (attributes.XsiTypeName != null) + { + dataContractName = attributes.XsiTypeName; + dataContractNamespace = attributes.XsiTypeNamespace; + } + + if (IsReadingCollectionExtensionData(xmlReader)) + { + Read(xmlReader); + dataNode = ReadUnknownCollectionData(xmlReader, dataContractName, dataContractNamespace); + } + else if (attributes.FactoryTypeName != null) + { + Read(xmlReader); + dataNode = ReadUnknownISerializableData(xmlReader, dataContractName, dataContractNamespace); + } + else if (IsReadingClassExtensionData(xmlReader)) + { + Read(xmlReader); + dataNode = ReadUnknownClassData(xmlReader, dataContractName, dataContractNamespace); + } + else + { + DataContract dataContract = ResolveDataContractFromTypeName(); + + if (dataContract == null) + { + dataNode = ReadExtensionDataValue(xmlReader, dataContractName, dataContractNamespace); + } + else if (dataContract is XmlDataContract) + { + dataNode = ReadUnknownXmlData(xmlReader, dataContractName, dataContractNamespace); + } + else + { + if (dataContract.IsISerializable) + { + Read(xmlReader); + dataNode = ReadUnknownISerializableData(xmlReader, dataContractName, dataContractNamespace); + } + else if (dataContract is PrimitiveDataContract) + { + if (attributes.Id == Globals.NewObjectId) + { + Read(xmlReader); + xmlReader.MoveToContent(); + dataNode = ReadUnknownPrimitiveData(xmlReader, dataContract.UnderlyingType, dataContractName, dataContractNamespace); + xmlReader.ReadEndElement(); + } + else + { + dataNode = new DataNode(xmlReader.ReadElementContentAsAnyType(dataContract.UnderlyingType)); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + } + } + else if (dataContract is EnumDataContract) + { + dataNode = new DataNode(((EnumDataContract)dataContract).ReadEnumValue(xmlReader)); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + } + else if (dataContract is ClassDataContract) + { + Read(xmlReader); + dataNode = ReadUnknownClassData(xmlReader, dataContractName, dataContractNamespace); + } + else if (dataContract is CollectionDataContract) + { + Read(xmlReader); + dataNode = ReadUnknownCollectionData(xmlReader, dataContractName, dataContractNamespace); + } + } + } + } + return dataNode; + } + + protected virtual void StartReadExtensionDataValue(XmlReaderDelegator xmlReader) + { + } + + private IDataNode ReadExtensionDataValue(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace) + { + StartReadExtensionDataValue(xmlReader); + + if (attributes.UnrecognizedAttributesFound) + { + return ReadUnknownXmlData(xmlReader, dataContractName, dataContractNamespace); + } + + IDictionary namespacesInScope = xmlReader.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml); + Read(xmlReader); + xmlReader.MoveToContent(); + + switch (xmlReader.NodeType) + { + case XmlNodeType.Text: + return ReadPrimitiveExtensionDataValue(xmlReader, dataContractName, dataContractNamespace); + case XmlNodeType.Element: + if (xmlReader.NamespaceURI.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal)) + { + return ReadUnknownClassData(xmlReader, dataContractName, dataContractNamespace); + } + else + { + return ReadAndResolveUnknownXmlData(xmlReader, namespacesInScope, dataContractName, dataContractNamespace); + } + + case XmlNodeType.EndElement: + { + // NOTE: cannot distinguish between empty class or IXmlSerializable and typeof(object) + IDataNode objNode = ReadUnknownPrimitiveData(xmlReader, Globals.TypeOfObject, dataContractName, dataContractNamespace); + xmlReader.ReadEndElement(); + objNode.IsFinalValue = false; + return objNode; + } + default: + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + } + + protected virtual IDataNode ReadPrimitiveExtensionDataValue(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace) + { + Type valueType = xmlReader.ValueType; + if (valueType == Globals.TypeOfString) + { + // NOTE: cannot distinguish other primitives from string (default XmlReader ValueType) + IDataNode stringNode = new DataNode(xmlReader.ReadContentAsString()); + InitializeExtensionDataNode(stringNode, dataContractName, dataContractNamespace); + stringNode.IsFinalValue = false; + xmlReader.ReadEndElement(); + return stringNode; + } + else + { + IDataNode objNode = ReadUnknownPrimitiveData(xmlReader, valueType, dataContractName, dataContractNamespace); + xmlReader.ReadEndElement(); + return objNode; + } + } + + protected void InitializeExtensionDataNode(IDataNode dataNode, string dataContractName, string dataContractNamespace) + { + dataNode.DataContractName = dataContractName; + dataNode.DataContractNamespace = dataContractNamespace; + dataNode.ClrAssemblyName = attributes.ClrAssembly; + dataNode.ClrTypeName = attributes.ClrType; + AddNewObject(dataNode); + dataNode.Id = attributes.Id; + } + + private IDataNode ReadUnknownPrimitiveData(XmlReaderDelegator xmlReader, Type type, string dataContractName, string dataContractNamespace) + { + IDataNode dataNode = xmlReader.ReadExtensionData(type); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + return dataNode; + } + + private ClassDataNode ReadUnknownClassData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace) + { + ClassDataNode dataNode = new ClassDataNode(); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + + int memberIndex = 0; + XmlNodeType nodeType; + while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement) + { + if (nodeType != XmlNodeType.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + if (dataNode.Members == null) + { + dataNode.Members = new List(); + } + + dataNode.Members.Add(ReadExtensionDataMember(xmlReader, memberIndex++)); + } + xmlReader.ReadEndElement(); + return dataNode; + } + + private CollectionDataNode ReadUnknownCollectionData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace) + { + CollectionDataNode dataNode = new CollectionDataNode(); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + + int arraySize = attributes.ArraySZSize; + XmlNodeType nodeType; + while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement) + { + if (nodeType != XmlNodeType.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + if (dataNode.ItemName == null) + { + dataNode.ItemName = xmlReader.LocalName; + dataNode.ItemNamespace = xmlReader.NamespaceURI; + } + if (xmlReader.IsStartElement(dataNode.ItemName, dataNode.ItemNamespace)) + { + if (dataNode.Items == null) + { + dataNode.Items = new List(); + } + + dataNode.Items.Add(ReadExtensionDataValue(xmlReader)); + } + else + { + SkipUnknownElement(xmlReader); + } + } + xmlReader.ReadEndElement(); + + if (arraySize != -1) + { + dataNode.Size = arraySize; + if (dataNode.Items == null) + { + if (dataNode.Size > 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArraySizeAttributeIncorrect, arraySize, 0))); + } + } + else if (dataNode.Size != dataNode.Items.Count) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArraySizeAttributeIncorrect, arraySize, dataNode.Items.Count))); + } + } + else + { + if (dataNode.Items != null) + { + dataNode.Size = dataNode.Items.Count; + } + else + { + dataNode.Size = 0; + } + } + + return dataNode; + } + + private ISerializableDataNode ReadUnknownISerializableData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace) + { + ISerializableDataNode dataNode = new ISerializableDataNode(); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + + dataNode.FactoryTypeName = attributes.FactoryTypeName; + dataNode.FactoryTypeNamespace = attributes.FactoryTypeNamespace; + + XmlNodeType nodeType; + while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement) + { + if (nodeType != XmlNodeType.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + if (xmlReader.NamespaceURI.Length != 0) + { + SkipUnknownElement(xmlReader); + continue; + } + + ISerializableDataMember member = new ISerializableDataMember + { + Name = xmlReader.LocalName, + Value = ReadExtensionDataValue(xmlReader) + }; + if (dataNode.Members == null) + { + dataNode.Members = new List(); + } + + dataNode.Members.Add(member); + } + xmlReader.ReadEndElement(); + return dataNode; + } + + private IDataNode ReadUnknownXmlData(XmlReaderDelegator xmlReader, string dataContractName, string dataContractNamespace) + { + XmlDataNode dataNode = new XmlDataNode(); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + dataNode.OwnerDocument = Document; + + if (xmlReader.NodeType == XmlNodeType.EndElement) + { + return dataNode; + } + + IList xmlAttributes = null; + IList xmlChildNodes = null; + + XmlNodeType nodeType = xmlReader.MoveToContent(); + if (nodeType != XmlNodeType.Text) + { + while (xmlReader.MoveToNextAttribute()) + { + string ns = xmlReader.NamespaceURI; + if (ns != Globals.SerializationNamespace && ns != Globals.SchemaInstanceNamespace) + { + if (xmlAttributes == null) + { + xmlAttributes = new List(); + } + + xmlAttributes.Add((XmlAttribute)Document.ReadNode(xmlReader.UnderlyingReader)); + } + } + Read(xmlReader); + } + + while ((nodeType = xmlReader.MoveToContent()) != XmlNodeType.EndElement) + { + if (xmlReader.EOF) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnexpectedEndOfFile))); + } + + if (xmlChildNodes == null) + { + xmlChildNodes = new List(); + } + + xmlChildNodes.Add(Document.ReadNode(xmlReader.UnderlyingReader)); + } + xmlReader.ReadEndElement(); + + dataNode.XmlAttributes = xmlAttributes; + dataNode.XmlChildNodes = xmlChildNodes; + return dataNode; + } + + // Pattern-recognition logic: the method reads XML elements into DOM. To recognize as an array, it requires that + // all items have the same name and namespace. To recognize as an ISerializable type, it requires that all + // items be unqualified. If the XML only contains elements (no attributes or other nodes) is recognized as a + // class/class hierarchy. Otherwise it is deserialized as XML. + private IDataNode ReadAndResolveUnknownXmlData(XmlReaderDelegator xmlReader, IDictionary namespaces, + string dataContractName, string dataContractNamespace) + { + bool couldBeISerializableData = true; + bool couldBeCollectionData = true; + bool couldBeClassData = true; + string elementNs = null, elementName = null; + IList xmlChildNodes = new List(); + IList xmlAttributes = null; + if (namespaces != null) + { + xmlAttributes = new List(); + foreach (KeyValuePair prefixNsPair in namespaces) + { + xmlAttributes.Add(AddNamespaceDeclaration(prefixNsPair.Key, prefixNsPair.Value)); + } + } + + XmlNodeType nodeType; + while ((nodeType = xmlReader.NodeType) != XmlNodeType.EndElement) + { + if (nodeType == XmlNodeType.Element) + { + string ns = xmlReader.NamespaceURI; + string name = xmlReader.LocalName; + if (couldBeISerializableData) + { + couldBeISerializableData = (ns.Length == 0); + } + + if (couldBeCollectionData) + { + if (elementName == null) + { + elementName = name; + elementNs = ns; + } + else + { + couldBeCollectionData = (string.CompareOrdinal(elementName, name) == 0) && + (string.CompareOrdinal(elementNs, ns) == 0); + } + } + } + else if (xmlReader.EOF) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnexpectedEndOfFile))); + } + else if (IsContentNode(xmlReader.NodeType)) + { + couldBeClassData = couldBeISerializableData = couldBeCollectionData = false; + } + + if (attributesInXmlData == null) + { + attributesInXmlData = new Attributes(); + } + + attributesInXmlData.Read(xmlReader); + + XmlNode childNode = Document.ReadNode(xmlReader.UnderlyingReader); + xmlChildNodes.Add(childNode); + + if (namespaces == null) + { + if (attributesInXmlData.XsiTypeName != null) + { + childNode.Attributes.Append(AddNamespaceDeclaration(attributesInXmlData.XsiTypePrefix, attributesInXmlData.XsiTypeNamespace)); + } + + if (attributesInXmlData.FactoryTypeName != null) + { + childNode.Attributes.Append(AddNamespaceDeclaration(attributesInXmlData.FactoryTypePrefix, attributesInXmlData.FactoryTypeNamespace)); + } + } + } + xmlReader.ReadEndElement(); + + if (elementName != null && couldBeCollectionData) + { + return ReadUnknownCollectionData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace); + } + else if (couldBeISerializableData) + { + return ReadUnknownISerializableData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace); + } + else if (couldBeClassData) + { + return ReadUnknownClassData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace); + } + else + { + XmlDataNode dataNode = new XmlDataNode(); + InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); + dataNode.OwnerDocument = Document; + dataNode.XmlChildNodes = xmlChildNodes; + dataNode.XmlAttributes = xmlAttributes; + return dataNode; + } + } + + private bool IsContentNode(XmlNodeType nodeType) + { + switch (nodeType) + { + case XmlNodeType.Whitespace: + case XmlNodeType.SignificantWhitespace: + case XmlNodeType.Comment: + case XmlNodeType.ProcessingInstruction: + case XmlNodeType.DocumentType: + return false; + default: + return true; + } + } + + internal XmlReaderDelegator CreateReaderOverChildNodes(IList xmlAttributes, IList xmlChildNodes) + { + XmlNode wrapperElement = CreateWrapperXmlElement(Document, xmlAttributes, xmlChildNodes, null, null, null); + XmlReaderDelegator nodeReader = CreateReaderDelegatorForReader(new XmlNodeReader(wrapperElement)); + nodeReader.MoveToContent(); + Read(nodeReader); + return nodeReader; + } + + internal static XmlNode CreateWrapperXmlElement(XmlDocument document, IList xmlAttributes, IList xmlChildNodes, string prefix, string localName, string ns) + { + localName = localName ?? "wrapper"; + ns = ns ?? string.Empty; + XmlNode wrapperElement = document.CreateElement(prefix, localName, ns); + if (xmlAttributes != null) + { + for (int i = 0; i < xmlAttributes.Count; i++) + { + wrapperElement.Attributes.Append(xmlAttributes[i]); + } + } + if (xmlChildNodes != null) + { + for (int i = 0; i < xmlChildNodes.Count; i++) + { + wrapperElement.AppendChild(xmlChildNodes[i]); + } + } + return wrapperElement; + } + + private XmlAttribute AddNamespaceDeclaration(string prefix, string ns) + { + XmlAttribute attribute = (prefix == null || prefix.Length == 0) ? + Document.CreateAttribute(null, Globals.XmlnsPrefix, Globals.XmlnsNamespace) : + Document.CreateAttribute(Globals.XmlnsPrefix, prefix, Globals.XmlnsNamespace); + attribute.Value = ns; + return attribute; + } + + public static Exception CreateUnexpectedStateException(XmlNodeType expectedState, XmlReaderDelegator xmlReader) + { + return XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.Format(SR.ExpectingState, expectedState), xmlReader); + } + + protected virtual object ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) + { + return dataContract.ReadXmlValue(reader, this); + } + + protected virtual XmlReaderDelegator CreateReaderDelegatorForReader(XmlReader xmlReader) + { + return new XmlReaderDelegator(xmlReader); + } + + protected virtual bool IsReadingCollectionExtensionData(XmlReaderDelegator xmlReader) + { + return (attributes.ArraySZSize != -1); + } + + protected virtual bool IsReadingClassExtensionData(XmlReaderDelegator xmlReader) + { + return false; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs new file mode 100644 index 0000000..170da38 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs @@ -0,0 +1,533 @@ +using System; +using System.Collections; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization.Formatters; + +namespace Compat.Runtime.Serialization +{ + internal class XmlObjectSerializerReadContextComplex : XmlObjectSerializerReadContext + { + private static readonly Hashtable dataContractTypeCache = new Hashtable(); + private readonly bool preserveObjectReferences; + protected IDataContractSurrogate dataContractSurrogate; + private readonly SerializationMode mode; + private readonly System.Runtime.Serialization.SerializationBinder binder; + private readonly System.Runtime.Serialization.ISurrogateSelector surrogateSelector; + private readonly FormatterAssemblyStyle assemblyFormat; + private Hashtable surrogateDataContracts; + + internal XmlObjectSerializerReadContextComplex( + DataContractSerializer serializer, + DataContract rootTypeDataContract, + System.Runtime.Serialization.DataContractResolver dataContractResolver) + : base(serializer, rootTypeDataContract, dataContractResolver) + { + mode = SerializationMode.SharedContract; + preserveObjectReferences = serializer.PreserveObjectReferences; + dataContractSurrogate = serializer.DataContractSurrogate; + } + + internal XmlObjectSerializerReadContextComplex(NetDataContractSerializer serializer) + : base(serializer) + { + mode = SerializationMode.SharedType; + preserveObjectReferences = true; + binder = serializer.Binder; + surrogateSelector = serializer.SurrogateSelector; + assemblyFormat = serializer.AssemblyFormat; + } + + internal XmlObjectSerializerReadContextComplex(XmlObjectSerializer serializer, int maxItemsInObjectGraph, System.Runtime.Serialization.StreamingContext streamingContext, bool ignoreExtensionDataObject) + : base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject) + { + } + + internal override SerializationMode Mode => mode; + + internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle) + { + DataContract dataContract = null; + if (mode == SerializationMode.SharedType && surrogateSelector != null) + { + dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, GetStreamingContext(), typeHandle, null /*type*/, ref surrogateDataContracts); + } + + if (dataContract != null) + { + if (IsGetOnlyCollection && dataContract is SurrogateDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + return dataContract; + } + + return base.GetDataContract(id, typeHandle); + } + + internal override DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = null; + if (mode == SerializationMode.SharedType && surrogateSelector != null) + { + dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, GetStreamingContext(), typeHandle, type, ref surrogateDataContracts); + } + + if (dataContract != null) + { + if (IsGetOnlyCollection && dataContract is SurrogateDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + return dataContract; + } + + return base.GetDataContract(typeHandle, type); + } + + public override object InternalDeserialize(XmlReaderDelegator xmlReader, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle, string name, string ns) + { + if (mode == SerializationMode.SharedContract) + { + if (dataContractSurrogate == null) + { + return base.InternalDeserialize(xmlReader, declaredTypeID, declaredTypeHandle, name, ns); + } + else + { + return InternalDeserializeWithSurrogate(xmlReader, Type.GetTypeFromHandle(declaredTypeHandle), null /*surrogateDataContract*/, name, ns); + } + } + else + { + return InternalDeserializeInSharedTypeMode(xmlReader, declaredTypeID, Type.GetTypeFromHandle(declaredTypeHandle), name, ns); + } + } + + internal override object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string name, string ns) + { + if (mode == SerializationMode.SharedContract) + { + if (dataContractSurrogate == null) + { + return base.InternalDeserialize(xmlReader, declaredType, name, ns); + } + else + { + return InternalDeserializeWithSurrogate(xmlReader, declaredType, null /*surrogateDataContract*/, name, ns); + } + } + else + { + return InternalDeserializeInSharedTypeMode(xmlReader, -1, declaredType, name, ns); + } + } + + internal override object InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, string name, string ns) + { + if (mode == SerializationMode.SharedContract) + { + if (dataContractSurrogate == null) + { + return base.InternalDeserialize(xmlReader, declaredType, dataContract, name, ns); + } + else + { + return InternalDeserializeWithSurrogate(xmlReader, declaredType, dataContract, name, ns); + } + } + else + { + return InternalDeserializeInSharedTypeMode(xmlReader, -1, declaredType, name, ns); + } + } + + private object InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, int declaredTypeID, Type declaredType, string name, string ns) + { + object retObj = null; + if (TryHandleNullOrRef(xmlReader, declaredType, name, ns, ref retObj)) + { + return retObj; + } + + DataContract dataContract; + string assemblyName = attributes.ClrAssembly; + string typeName = attributes.ClrType; + if (assemblyName != null && typeName != null) + { + dataContract = ResolveDataContractInSharedTypeMode(assemblyName, typeName, out Assembly assembly, out Type type); + if (dataContract == null) + { + if (assembly == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.AssemblyNotFound, assemblyName))); + } + + if (type == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ClrTypeNotFound, assembly.FullName, typeName))); + } + } + //Array covariance is not supported in XSD. If declared type is array, data is sent in format of base array + if (declaredType != null && declaredType.IsArray) + { + dataContract = (declaredTypeID < 0) ? GetDataContract(declaredType) : GetDataContract(declaredTypeID, declaredType.TypeHandle); + } + } + else + { + if (assemblyName != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrTypeLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName)))); + } + else if (typeName != null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrAssemblyLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName)))); + } + else if (declaredType == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrTypeLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName)))); + } + + dataContract = (declaredTypeID < 0) ? GetDataContract(declaredType) : GetDataContract(declaredTypeID, declaredType.TypeHandle); + } + return ReadDataContractValue(dataContract, xmlReader); + } + + private object InternalDeserializeWithSurrogate(XmlReaderDelegator xmlReader, Type declaredType, DataContract surrogateDataContract, string name, string ns) + { + DataContract dataContract = surrogateDataContract ?? + GetDataContract(DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, declaredType)); + if (IsGetOnlyCollection && dataContract.UnderlyingType != declaredType) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(declaredType)))); + } + ReadAttributes(xmlReader); + string objectId = GetObjectId(); + object oldObj = InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract); + object obj = DataContractSurrogateCaller.GetDeserializedObject(dataContractSurrogate, oldObj, dataContract.UnderlyingType, declaredType); + ReplaceDeserializedObject(objectId, oldObj, obj); + + return obj; + } + + private Type ResolveDataContractTypeInSharedTypeMode(string assemblyName, string typeName, out Assembly assembly) + { + assembly = null; + Type type = null; + + if (binder != null) + { + type = binder.BindToType(assemblyName, typeName); + } + + if (type == null) + { + XmlObjectDataContractTypeKey key = new XmlObjectDataContractTypeKey(assemblyName, typeName); + XmlObjectDataContractTypeInfo dataContractTypeInfo = (XmlObjectDataContractTypeInfo)dataContractTypeCache[key]; + if (dataContractTypeInfo == null) + { + if (assemblyFormat == FormatterAssemblyStyle.Full) + { + if (assemblyName == Globals.MscorlibAssemblyName) + { + assembly = Globals.TypeOfInt.Assembly; + } + else + { + assembly = Assembly.Load(assemblyName); + } + if (assembly != null) + { + type = assembly.GetType(typeName); + } + } + else + { + assembly = XmlObjectSerializerReadContextComplex.ResolveSimpleAssemblyName(assemblyName); + if (assembly != null) + { + // Catching any exceptions that could be thrown from a failure on assembly load + // This is necessary, for example, if there are generic parameters that are qualified with a version of the assembly that predates the one available + try + { + type = assembly.GetType(typeName); + } + catch (TypeLoadException) { } + catch (FileNotFoundException) { } + catch (FileLoadException) { } + catch (BadImageFormatException) { } + + if (type == null) + { + type = Type.GetType(typeName, XmlObjectSerializerReadContextComplex.ResolveSimpleAssemblyName, new TopLevelAssemblyTypeResolver(assembly).ResolveType, false /* throwOnError */); + } + } + } + + if (type != null) + { + CheckTypeForwardedTo(assembly, type.Assembly, type); + + dataContractTypeInfo = new XmlObjectDataContractTypeInfo(assembly, type); + lock (dataContractTypeCache) + { + if (!dataContractTypeCache.ContainsKey(key)) + { + dataContractTypeCache[key] = dataContractTypeInfo; + } + } + } + } + else + { + assembly = dataContractTypeInfo.Assembly; + type = dataContractTypeInfo.Type; + } + } + + return type; + } + + private DataContract ResolveDataContractInSharedTypeMode(string assemblyName, string typeName, out Assembly assembly, out Type type) + { + type = ResolveDataContractTypeInSharedTypeMode(assemblyName, typeName, out assembly); + if (type != null) + { + return GetDataContract(type); + } + + return null; + } + + protected override DataContract ResolveDataContractFromTypeName() + { + if (mode == SerializationMode.SharedContract) + { + return base.ResolveDataContractFromTypeName(); + } + else + { + if (attributes.ClrAssembly != null && attributes.ClrType != null) + { + return ResolveDataContractInSharedTypeMode(attributes.ClrAssembly, attributes.ClrType, out Assembly assembly, out Type type); + } + } + return null; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool CheckIfTypeSerializableForSharedTypeMode(Type memberType) + { + Fx.Assert(surrogateSelector != null, "Method should not be called when surrogateSelector is null."); + return (surrogateSelector.GetSurrogate(memberType, GetStreamingContext(), out System.Runtime.Serialization.ISurrogateSelector surrogateSelectorNotUsed) != null); + } + + internal override void CheckIfTypeSerializable(Type memberType, bool isMemberTypeSerializable) + { + if (mode == SerializationMode.SharedType && surrogateSelector != null && + CheckIfTypeSerializableForSharedTypeMode(memberType)) + { + return; + } + else + { + if (dataContractSurrogate != null) + { + while (memberType.IsArray) + { + memberType = memberType.GetElementType(); + } + + memberType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, memberType); + if (!DataContract.IsTypeSerializable(memberType)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.TypeNotSerializable, memberType))); + } + + return; + } + } + + base.CheckIfTypeSerializable(memberType, isMemberTypeSerializable); + } + + internal override Type GetSurrogatedType(Type type) + { + if (dataContractSurrogate == null) + { + return base.GetSurrogatedType(type); + } + else + { + type = DataContract.UnwrapNullableType(type); + Type surrogateType = DataContractSerializer.GetSurrogatedType(dataContractSurrogate, type); + if (IsGetOnlyCollection && surrogateType != type) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(type)))); + } + else + { + return surrogateType; + } + } + } + +#if USE_REFEMIT + public override int GetArraySize() +#else + internal override int GetArraySize() +#endif + { + return preserveObjectReferences ? attributes.ArraySZSize : -1; + } + + private static Assembly ResolveSimpleAssemblyName(AssemblyName assemblyName) + { + return ResolveSimpleAssemblyName(assemblyName.FullName); + } + + private static Assembly ResolveSimpleAssemblyName(string assemblyName) + { + Assembly assembly; + if (assemblyName == Globals.MscorlibAssemblyName) + { + assembly = Globals.TypeOfInt.Assembly; + } + else + { + assembly = Assembly.LoadWithPartialName(assemblyName); + if (assembly == null) + { + AssemblyName an = new AssemblyName(assemblyName) + { + Version = null + }; + assembly = Assembly.LoadWithPartialName(an.FullName); + } + } + return assembly; + } + + private static void CheckTypeForwardedTo(Assembly sourceAssembly, Assembly destinationAssembly, Type resolvedType) + { + if (sourceAssembly != destinationAssembly && !NetDataContractSerializer.UnsafeTypeForwardingEnabled && !sourceAssembly.IsFullyTrusted) + { + // We have a TypeForwardedTo attribute + //if (!destinationAssembly.PermissionSet.IsSubsetOf(sourceAssembly.PermissionSet)) + //{ + // // We look for a matching TypeForwardedFrom attribute + // TypeInformation typeInfo = NetDataContractSerializer.GetTypeInformation(resolvedType); + // if (typeInfo.HasTypeForwardedFrom) + // { + // Assembly typeForwardedFromAssembly = null; + // try + // { + // // if this Assembly.Load fails, we still want to throw security exception + // typeForwardedFromAssembly = Assembly.Load(typeInfo.AssemblyString); + // } + // catch { } + + // if (typeForwardedFromAssembly == sourceAssembly) + // { + // return; + // } + // } + // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotDeserializeForwardedType, DataContract.GetClrTypeFullName(resolvedType)))); + //} + } + } + + private sealed class TopLevelAssemblyTypeResolver + { + private readonly Assembly topLevelAssembly; + + public TopLevelAssemblyTypeResolver(Assembly topLevelAssembly) + { + this.topLevelAssembly = topLevelAssembly; + } + public Type ResolveType(Assembly assembly, string simpleTypeName, bool ignoreCase) + { + if (assembly == null) + { + assembly = topLevelAssembly; + } + + return assembly.GetType(simpleTypeName, false, ignoreCase); + } + } + + private class XmlObjectDataContractTypeInfo + { + private readonly Assembly assembly; + private readonly Type type; + public XmlObjectDataContractTypeInfo(Assembly assembly, Type type) + { + this.assembly = assembly; + this.type = type; + } + + public Assembly Assembly => assembly; + + public Type Type => type; + } + + private class XmlObjectDataContractTypeKey + { + private readonly string assemblyName; + private readonly string typeName; + public XmlObjectDataContractTypeKey(string assemblyName, string typeName) + { + this.assemblyName = assemblyName; + this.typeName = typeName; + } + + public override bool Equals(object obj) + { + if (object.ReferenceEquals(this, obj)) + { + return true; + } + + XmlObjectDataContractTypeKey other = obj as XmlObjectDataContractTypeKey; + if (other == null) + { + return false; + } + + if (assemblyName != other.assemblyName) + { + return false; + } + + if (typeName != other.typeName) + { + return false; + } + + return true; + } + + public override int GetHashCode() + { + int hashCode = 0; + if (assemblyName != null) + { + hashCode = assemblyName.GetHashCode(); + } + + if (typeName != null) + { + hashCode ^= typeName.GetHashCode(); + } + + return hashCode; + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContext.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContext.cs new file mode 100644 index 0000000..caf8b0f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContext.cs @@ -0,0 +1,863 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.Security; +using System.Security.Permissions; +using System.Runtime.CompilerServices; + +namespace Compat.Runtime.Serialization +{ + internal class XmlObjectSerializerWriteContext : XmlObjectSerializerContext + { + private ObjectReferenceStack byValObjectsInScope = new ObjectReferenceStack(); + private XmlSerializableWriter xmlSerializableWriter; + private const int depthToCheckCyclicReference = 512; + protected bool preserveObjectReferences; + private ObjectToIdCache serializedObjects; + private bool isGetOnlyCollection; + private readonly bool unsafeTypeForwardingEnabled; + protected bool serializeReadOnlyTypes; + + internal static XmlObjectSerializerWriteContext CreateContext(DataContractSerializer serializer, DataContract rootTypeDataContract, System.Runtime.Serialization.DataContractResolver dataContractResolver) + { + return (serializer.PreserveObjectReferences || serializer.DataContractSurrogate != null) + ? new XmlObjectSerializerWriteContextComplex(serializer, rootTypeDataContract, dataContractResolver) + : new XmlObjectSerializerWriteContext(serializer, rootTypeDataContract, dataContractResolver); + } + + internal static XmlObjectSerializerWriteContext CreateContext(NetDataContractSerializer serializer, Hashtable surrogateDataContracts) + { + return new XmlObjectSerializerWriteContextComplex(serializer, surrogateDataContracts); + } + + protected XmlObjectSerializerWriteContext( + DataContractSerializer serializer, + DataContract rootTypeDataContract, + System.Runtime.Serialization.DataContractResolver resolver) + : base(serializer, rootTypeDataContract, resolver) + { + serializeReadOnlyTypes = serializer.SerializeReadOnlyTypes; + // Known types restricts the set of types that can be deserialized + unsafeTypeForwardingEnabled = true; + } + + protected XmlObjectSerializerWriteContext(NetDataContractSerializer serializer) + : base(serializer) + { + unsafeTypeForwardingEnabled = NetDataContractSerializer.UnsafeTypeForwardingEnabled; + } + + internal XmlObjectSerializerWriteContext( + XmlObjectSerializer serializer, + int maxItemsInObjectGraph, + System.Runtime.Serialization.StreamingContext streamingContext, + bool ignoreExtensionDataObject) + : base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject) + { + // Known types restricts the set of types that can be deserialized + unsafeTypeForwardingEnabled = true; + } + + protected ObjectToIdCache SerializedObjects + { + get + { + if (serializedObjects == null) + { + serializedObjects = new ObjectToIdCache(); + } + + return serializedObjects; + } + } + + internal override bool IsGetOnlyCollection + { + get => isGetOnlyCollection; + set => isGetOnlyCollection = value; + } + + internal bool SerializeReadOnlyTypes => serializeReadOnlyTypes; + + internal bool UnsafeTypeForwardingEnabled => unsafeTypeForwardingEnabled; + +#if USE_REFEMIT + public void StoreIsGetOnlyCollection() +#else + internal void StoreIsGetOnlyCollection() +#endif + { + isGetOnlyCollection = true; + } + + public void InternalSerializeReference(XmlWriterDelegator xmlWriter, object obj, bool isDeclaredType, bool writeXsiType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle) + { + if (!OnHandleReference(xmlWriter, obj, true /*canContainCyclicReference*/)) + { + InternalSerialize(xmlWriter, obj, isDeclaredType, writeXsiType, declaredTypeID, declaredTypeHandle); + } + + OnEndHandleReference(xmlWriter, obj, true /*canContainCyclicReference*/); + } + + public virtual void InternalSerialize(XmlWriterDelegator xmlWriter, object obj, bool isDeclaredType, bool writeXsiType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle) + { + if (writeXsiType) + { + Type declaredType = Globals.TypeOfObject; + SerializeWithXsiType(xmlWriter, obj, Type.GetTypeHandle(obj), null/*type*/, -1, declaredType.TypeHandle, declaredType); + } + else if (isDeclaredType) + { + DataContract contract = GetDataContract(declaredTypeID, declaredTypeHandle); + SerializeWithoutXsiType(contract, xmlWriter, obj, declaredTypeHandle); + } + else + { + RuntimeTypeHandle objTypeHandle = Type.GetTypeHandle(obj); + if (declaredTypeHandle.Equals(objTypeHandle)) + { + DataContract dataContract = (declaredTypeID >= 0) + ? GetDataContract(declaredTypeID, declaredTypeHandle) + : GetDataContract(declaredTypeHandle, null /*type*/); + SerializeWithoutXsiType(dataContract, xmlWriter, obj, declaredTypeHandle); + } + else + { + SerializeWithXsiType(xmlWriter, obj, objTypeHandle, null /*type*/, declaredTypeID, declaredTypeHandle, Type.GetTypeFromHandle(declaredTypeHandle)); + } + } + } + + internal void SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle declaredTypeHandle) + { + if (OnHandleIsReference(xmlWriter, dataContract, obj)) + { + return; + } + + if (dataContract.KnownDataContracts != null) + { + scopedKnownTypes.Push(dataContract.KnownDataContracts); + WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle); + scopedKnownTypes.Pop(); + } + else + { + WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle); + } + } + + internal virtual void SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) + { + bool verifyKnownType = false; + Type declaredType = rootTypeDataContract.OriginalUnderlyingType; + + if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType)) + { + if (DataContractResolver != null) + { + WriteResolvedTypeInfo(xmlWriter, graphType, declaredType); + } + } + else if (!declaredType.IsArray) //Array covariance is not supported in XSD. If declared type is array do not write xsi:type. Instead write xsi:type for each item + { + verifyKnownType = WriteTypeInfo(xmlWriter, dataContract, rootTypeDataContract); + } + SerializeAndVerifyType(dataContract, xmlWriter, obj, verifyKnownType, originalDeclaredTypeHandle, declaredType); + } + + protected virtual void SerializeWithXsiType(XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType) + { + DataContract dataContract; + bool verifyKnownType = false; + if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType)) + { + dataContract = GetDataContractSkipValidation(DataContract.GetId(objectTypeHandle), objectTypeHandle, objectType); + if (OnHandleIsReference(xmlWriter, dataContract, obj)) + { + return; + } + + if (Mode == SerializationMode.SharedType && dataContract.IsValidContract(Mode)) + { + dataContract = dataContract.GetValidContract(Mode); + } + else + { + dataContract = GetDataContract(declaredTypeHandle, declaredType); + } + + if (!WriteClrTypeInfo(xmlWriter, dataContract) && DataContractResolver != null) + { + if (objectType == null) + { + objectType = Type.GetTypeFromHandle(objectTypeHandle); + } + WriteResolvedTypeInfo(xmlWriter, objectType, declaredType); + } + } + else if (declaredType.IsArray)//Array covariance is not supported in XSD. If declared type is array do not write xsi:type. Instead write xsi:type for each item + { + // A call to OnHandleIsReference is not necessary here -- arrays cannot be IsReference + dataContract = GetDataContract(objectTypeHandle, objectType); + WriteClrTypeInfo(xmlWriter, dataContract); + dataContract = GetDataContract(declaredTypeHandle, declaredType); + } + else + { + dataContract = GetDataContract(objectTypeHandle, objectType); + if (OnHandleIsReference(xmlWriter, dataContract, obj)) + { + return; + } + + if (!WriteClrTypeInfo(xmlWriter, dataContract)) + { + DataContract declaredTypeContract = (declaredTypeID >= 0) + ? GetDataContract(declaredTypeID, declaredTypeHandle) + : GetDataContract(declaredTypeHandle, declaredType); + verifyKnownType = WriteTypeInfo(xmlWriter, dataContract, declaredTypeContract); + } + } + + SerializeAndVerifyType(dataContract, xmlWriter, obj, verifyKnownType, declaredTypeHandle, declaredType); + } + + internal bool OnHandleIsReference(XmlWriterDelegator xmlWriter, DataContract contract, object obj) + { + if (preserveObjectReferences || !contract.IsReference || isGetOnlyCollection) + { + return false; + } + + bool isNew = true; + int objectId = SerializedObjects.GetId(obj, ref isNew); + byValObjectsInScope.EnsureSetAsIsReference(obj); + if (isNew) + { + xmlWriter.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.IdLocalName, + DictionaryGlobals.SerializationNamespace, string.Format(CultureInfo.InvariantCulture, "{0}{1}", "i", objectId)); + return false; + } + else + { + xmlWriter.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.RefLocalName, DictionaryGlobals.SerializationNamespace, string.Format(CultureInfo.InvariantCulture, "{0}{1}", "i", objectId)); + return true; + } + } + + protected void SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, bool verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) + { + bool knownTypesAddedInCurrentScope = false; + if (dataContract.KnownDataContracts != null) + { + scopedKnownTypes.Push(dataContract.KnownDataContracts); + knownTypesAddedInCurrentScope = true; + } + + if (verifyKnownType) + { + if (!IsKnownType(dataContract, declaredType)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.StableName.Name, dataContract.StableName.Namespace))); + } + } + WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle); + + if (knownTypesAddedInCurrentScope) + { + scopedKnownTypes.Pop(); + } + } + + internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, DataContract dataContract) + { + return false; + } + + internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, string clrTypeName, string clrAssemblyName) + { + return false; + } + + internal virtual bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, System.Runtime.Serialization.SerializationInfo serInfo) + { + return false; + } + + public virtual void WriteAnyType(XmlWriterDelegator xmlWriter, object value) + { + xmlWriter.WriteAnyType(value); + } + + public virtual void WriteString(XmlWriterDelegator xmlWriter, string value) + { + xmlWriter.WriteString(value); + } + public virtual void WriteString(XmlWriterDelegator xmlWriter, string value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(string), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + xmlWriter.WriteStartElementPrimitive(name, ns); + xmlWriter.WriteString(value); + xmlWriter.WriteEndElementPrimitive(); + } + } + + public virtual void WriteBase64(XmlWriterDelegator xmlWriter, byte[] value) + { + xmlWriter.WriteBase64(value); + } + public virtual void WriteBase64(XmlWriterDelegator xmlWriter, byte[] value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(byte[]), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + xmlWriter.WriteStartElementPrimitive(name, ns); + xmlWriter.WriteBase64(value); + xmlWriter.WriteEndElementPrimitive(); + } + } + + public virtual void WriteUri(XmlWriterDelegator xmlWriter, Uri value) + { + xmlWriter.WriteUri(value); + } + public virtual void WriteUri(XmlWriterDelegator xmlWriter, Uri value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(Uri), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + xmlWriter.WriteStartElementPrimitive(name, ns); + xmlWriter.WriteUri(value); + xmlWriter.WriteEndElementPrimitive(); + } + } + + public virtual void WriteQName(XmlWriterDelegator xmlWriter, XmlQualifiedName value) + { + xmlWriter.WriteQName(value); + } + public virtual void WriteQName(XmlWriterDelegator xmlWriter, XmlQualifiedName value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(XmlQualifiedName), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + if (ns != null && ns.Value != null && ns.Value.Length > 0) + { + xmlWriter.WriteStartElement(Globals.ElementPrefix, name, ns); + } + else + { + xmlWriter.WriteStartElement(name, ns); + } + + xmlWriter.WriteQName(value); + xmlWriter.WriteEndElement(); + } + } + + internal void HandleGraphAtTopLevel(XmlWriterDelegator writer, object obj, DataContract contract) + { + writer.WriteXmlnsAttribute(Globals.XsiPrefix, DictionaryGlobals.SchemaInstanceNamespace); + if (contract.IsISerializable) + { + writer.WriteXmlnsAttribute(Globals.XsdPrefix, DictionaryGlobals.SchemaNamespace); + } + + OnHandleReference(writer, obj, true /*canContainReferences*/); + } + + internal virtual bool OnHandleReference(XmlWriterDelegator xmlWriter, object obj, bool canContainCyclicReference) + { + if (xmlWriter._depth < depthToCheckCyclicReference) + { + return false; + } + + if (canContainCyclicReference) + { + if (byValObjectsInScope.Contains(obj)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotSerializeObjectWithCycles, DataContract.GetClrTypeFullName(obj.GetType())))); + } + + byValObjectsInScope.Push(obj); + } + return false; + } + + internal virtual void OnEndHandleReference(XmlWriterDelegator xmlWriter, object obj, bool canContainCyclicReference) + { + if (xmlWriter._depth < depthToCheckCyclicReference) + { + return; + } + + if (canContainCyclicReference) + { + byValObjectsInScope.Pop(obj); + } + } + + public void WriteNull(XmlWriterDelegator xmlWriter, Type memberType, bool isMemberTypeSerializable) + { + CheckIfTypeSerializable(memberType, isMemberTypeSerializable); + WriteNull(xmlWriter); + } + + internal void WriteNull(XmlWriterDelegator xmlWriter, Type memberType, bool isMemberTypeSerializable, XmlDictionaryString name, XmlDictionaryString ns) + { + xmlWriter.WriteStartElement(name, ns); + WriteNull(xmlWriter, memberType, isMemberTypeSerializable); + xmlWriter.WriteEndElement(); + } + + public void IncrementArrayCount(XmlWriterDelegator xmlWriter, Array array) + { + IncrementCollectionCount(xmlWriter, array.GetLength(0)); + } + + public void IncrementCollectionCount(XmlWriterDelegator xmlWriter, ICollection collection) + { + IncrementCollectionCount(xmlWriter, collection.Count); + } + + public void IncrementCollectionCountGeneric(XmlWriterDelegator xmlWriter, ICollection collection) + { + IncrementCollectionCount(xmlWriter, collection.Count); + } + + private void IncrementCollectionCount(XmlWriterDelegator xmlWriter, int size) + { + IncrementItemCount(size); + WriteArraySize(xmlWriter, size); + } + + internal virtual void WriteArraySize(XmlWriterDelegator xmlWriter, int size) + { + } + + public static T GetDefaultValue() + { + return default(T); + } + + public static T GetNullableValue(Nullable value) where T : struct + { + // value.Value will throw if hasValue is false + return value.Value; + } + + public static void ThrowRequiredMemberMustBeEmitted(string memberName, Type type) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Runtime.Serialization.SerializationException(SR.Format(SR.RequiredMemberMustBeEmitted, memberName, type.FullName))); + } + + public static bool GetHasValue(Nullable value) where T : struct + { + return value.HasValue; + } + + internal void WriteIXmlSerializable(XmlWriterDelegator xmlWriter, object obj) + { + if (xmlSerializableWriter == null) + { + xmlSerializableWriter = new XmlSerializableWriter(); + } + + WriteIXmlSerializable(xmlWriter, obj, xmlSerializableWriter); + } + + internal static void WriteRootIXmlSerializable(XmlWriterDelegator xmlWriter, object obj) + { + WriteIXmlSerializable(xmlWriter, obj, new XmlSerializableWriter()); + } + + private static void WriteIXmlSerializable(XmlWriterDelegator xmlWriter, object obj, XmlSerializableWriter xmlSerializableWriter) + { + xmlSerializableWriter.BeginWrite(xmlWriter.Writer, obj); + IXmlSerializable xmlSerializable = obj as IXmlSerializable; + if (xmlSerializable != null) + { + xmlSerializable.WriteXml(xmlSerializableWriter); + } + else + { + XmlElement xmlElement = obj as XmlElement; + if (xmlElement != null) + { + xmlElement.WriteTo(xmlSerializableWriter); + } + else + { + XmlNode[] xmlNodes = obj as XmlNode[]; + if (xmlNodes != null) + { + foreach (XmlNode xmlNode in xmlNodes) + { + xmlNode.WriteTo(xmlSerializableWriter); + } + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnknownXmlType, DataContract.GetClrTypeFullName(obj.GetType())))); + } + } + } + xmlSerializableWriter.EndWrite(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + internal void GetObjectData( + System.Runtime.Serialization.ISerializable obj, + System.Runtime.Serialization.SerializationInfo serInfo, + System.Runtime.Serialization.StreamingContext context) + { + // Demand the serialization formatter permission every time + //Globals.SerializationFormatterPermission.Demand(); + obj.GetObjectData(serInfo, context); + } + + public void WriteISerializable(XmlWriterDelegator xmlWriter, System.Runtime.Serialization.ISerializable obj) + { + Type objType = obj.GetType(); + System.Runtime.Serialization.SerializationInfo serInfo = new System.Runtime.Serialization.SerializationInfo(objType, XmlObjectSerializer.FormatterConverter, !UnsafeTypeForwardingEnabled); + GetObjectData(obj, serInfo, GetStreamingContext()); + + if (!UnsafeTypeForwardingEnabled && serInfo.AssemblyName == Globals.MscorlibAssemblyName) + { + // Throw if a malicious type tries to set its assembly name to "0" to get deserialized in mscorlib + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ISerializableAssemblyNameSetToZero, DataContract.GetClrTypeFullName(obj.GetType())))); + } + + WriteSerializationInfo(xmlWriter, objType, serInfo); + } + + internal void WriteSerializationInfo(XmlWriterDelegator xmlWriter, Type objType, System.Runtime.Serialization.SerializationInfo serInfo) + { + if (DataContract.GetClrTypeFullName(objType) != serInfo.FullTypeName) + { + if (DataContractResolver != null) + { + if (ResolveType(serInfo.ObjectType, objType, out XmlDictionaryString typeName, out XmlDictionaryString typeNs)) + { + xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, typeName, typeNs); + } + } + else + { + DataContract.GetDefaultStableName(serInfo.FullTypeName, out string typeName, out string typeNs); + xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(typeName), DataContract.GetClrTypeString(typeNs)); + } + } + + WriteClrTypeInfo(xmlWriter, objType, serInfo); + IncrementItemCount(serInfo.MemberCount); + foreach (System.Runtime.Serialization.SerializationEntry serEntry in serInfo) + { + XmlDictionaryString name = DataContract.GetClrTypeString(DataContract.EncodeLocalName(serEntry.Name)); + xmlWriter.WriteStartElement(name, DictionaryGlobals.EmptyString); + object obj = serEntry.Value; + if (obj == null) + { + WriteNull(xmlWriter); + } + else + { + InternalSerializeReference(xmlWriter, obj, false /*isDeclaredType*/, false /*writeXsiType*/, -1, Globals.TypeOfObject.TypeHandle); + } + + xmlWriter.WriteEndElement(); + } + } + + public void WriteExtensionData(XmlWriterDelegator xmlWriter, ExtensionDataObject extensionData, int memberIndex) + { + if (IgnoreExtensionDataObject || extensionData == null) + { + return; + } + + IList members = extensionData.Members; + if (members != null) + { + for (int i = 0; i < extensionData.Members.Count; i++) + { + ExtensionDataMember member = extensionData.Members[i]; + if (member.MemberIndex == memberIndex) + { + WriteExtensionDataMember(xmlWriter, member); + } + } + } + } + + private void WriteExtensionDataMember(XmlWriterDelegator xmlWriter, ExtensionDataMember member) + { + xmlWriter.WriteStartElement(member.Name, member.Namespace); + IDataNode dataNode = member.Value; + WriteExtensionDataValue(xmlWriter, dataNode); + xmlWriter.WriteEndElement(); + } + + internal virtual void WriteExtensionDataTypeInfo(XmlWriterDelegator xmlWriter, IDataNode dataNode) + { + if (dataNode.DataContractName != null) + { + WriteTypeInfo(xmlWriter, dataNode.DataContractName, dataNode.DataContractNamespace); + } + + WriteClrTypeInfo(xmlWriter, dataNode.DataType, dataNode.ClrTypeName, dataNode.ClrAssemblyName); + } + + internal void WriteExtensionDataValue(XmlWriterDelegator xmlWriter, IDataNode dataNode) + { + IncrementItemCount(1); + if (dataNode == null) + { + WriteNull(xmlWriter); + return; + } + + if (dataNode.PreservesReferences + && OnHandleReference(xmlWriter, (dataNode.Value == null ? dataNode : dataNode.Value), true /*canContainCyclicReference*/)) + { + return; + } + + Type dataType = dataNode.DataType; + if (dataType == Globals.TypeOfClassDataNode) + { + WriteExtensionClassData(xmlWriter, (ClassDataNode)dataNode); + } + else if (dataType == Globals.TypeOfCollectionDataNode) + { + WriteExtensionCollectionData(xmlWriter, (CollectionDataNode)dataNode); + } + else if (dataType == Globals.TypeOfXmlDataNode) + { + WriteExtensionXmlData(xmlWriter, (XmlDataNode)dataNode); + } + else if (dataType == Globals.TypeOfISerializableDataNode) + { + WriteExtensionISerializableData(xmlWriter, (ISerializableDataNode)dataNode); + } + else + { + WriteExtensionDataTypeInfo(xmlWriter, dataNode); + + if (dataType == Globals.TypeOfObject) + { + // NOTE: serialize value in DataNode since it may contain non-primitive + // deserialized object (ex. empty class) + object o = dataNode.Value; + if (o != null) + { + InternalSerialize(xmlWriter, o, false /*isDeclaredType*/, false /*writeXsiType*/, -1, o.GetType().TypeHandle); + } + } + else + { + xmlWriter.WriteExtensionData(dataNode); + } + } + if (dataNode.PreservesReferences) + { + OnEndHandleReference(xmlWriter, (dataNode.Value == null ? dataNode : dataNode.Value), true /*canContainCyclicReference*/); + } + } + + internal bool TryWriteDeserializedExtensionData(XmlWriterDelegator xmlWriter, IDataNode dataNode) + { + object o = dataNode.Value; + if (o == null) + { + return false; + } + + Type declaredType = (dataNode.DataContractName == null) ? o.GetType() : Globals.TypeOfObject; + InternalSerialize(xmlWriter, o, false /*isDeclaredType*/, false /*writeXsiType*/, -1, declaredType.TypeHandle); + return true; + } + + private void WriteExtensionClassData(XmlWriterDelegator xmlWriter, ClassDataNode dataNode) + { + if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode)) + { + WriteExtensionDataTypeInfo(xmlWriter, dataNode); + + IList members = dataNode.Members; + if (members != null) + { + for (int i = 0; i < members.Count; i++) + { + WriteExtensionDataMember(xmlWriter, members[i]); + } + } + } + } + + private void WriteExtensionCollectionData(XmlWriterDelegator xmlWriter, CollectionDataNode dataNode) + { + if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode)) + { + WriteExtensionDataTypeInfo(xmlWriter, dataNode); + + WriteArraySize(xmlWriter, dataNode.Size); + + IList items = dataNode.Items; + if (items != null) + { + for (int i = 0; i < items.Count; i++) + { + xmlWriter.WriteStartElement(dataNode.ItemName, dataNode.ItemNamespace); + WriteExtensionDataValue(xmlWriter, items[i]); + xmlWriter.WriteEndElement(); + } + } + } + } + + private void WriteExtensionISerializableData(XmlWriterDelegator xmlWriter, ISerializableDataNode dataNode) + { + if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode)) + { + WriteExtensionDataTypeInfo(xmlWriter, dataNode); + + if (dataNode.FactoryTypeName != null) + { + xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, dataNode.FactoryTypeName, dataNode.FactoryTypeNamespace); + } + + IList members = dataNode.Members; + if (members != null) + { + for (int i = 0; i < members.Count; i++) + { + ISerializableDataMember member = members[i]; + xmlWriter.WriteStartElement(member.Name, string.Empty); + WriteExtensionDataValue(xmlWriter, member.Value); + xmlWriter.WriteEndElement(); + } + } + } + } + + private void WriteExtensionXmlData(XmlWriterDelegator xmlWriter, XmlDataNode dataNode) + { + if (!TryWriteDeserializedExtensionData(xmlWriter, dataNode)) + { + IList xmlAttributes = dataNode.XmlAttributes; + if (xmlAttributes != null) + { + foreach (XmlAttribute attribute in xmlAttributes) + { + attribute.WriteTo(xmlWriter.Writer); + } + } + WriteExtensionDataTypeInfo(xmlWriter, dataNode); + + IList xmlChildNodes = dataNode.XmlChildNodes; + if (xmlChildNodes != null) + { + foreach (XmlNode node in xmlChildNodes) + { + node.WriteTo(xmlWriter.Writer); + } + } + } + } + + protected virtual void WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle declaredTypeHandle) + { + dataContract.WriteXmlValue(xmlWriter, obj, this); + } + + protected virtual void WriteNull(XmlWriterDelegator xmlWriter) + { + XmlObjectSerializer.WriteNull(xmlWriter); + } + + private void WriteResolvedTypeInfo(XmlWriterDelegator writer, Type objectType, Type declaredType) + { + if (ResolveType(objectType, declaredType, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)) + { + WriteTypeInfo(writer, typeName, typeNamespace); + } + } + + private bool ResolveType(Type objectType, Type declaredType, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) + { + if (!DataContractResolver.TryResolveType(objectType, declaredType, KnownTypeResolver, out typeName, out typeNamespace)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ResolveTypeReturnedFalse, DataContract.GetClrTypeFullName(DataContractResolver.GetType()), DataContract.GetClrTypeFullName(objectType)))); + } + if (typeName == null) + { + if (typeNamespace == null) + { + return false; + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ResolveTypeReturnedNull, DataContract.GetClrTypeFullName(DataContractResolver.GetType()), DataContract.GetClrTypeFullName(objectType)))); + } + } + if (typeNamespace == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ResolveTypeReturnedNull, DataContract.GetClrTypeFullName(DataContractResolver.GetType()), DataContract.GetClrTypeFullName(objectType)))); + } + return true; + } + + protected virtual bool WriteTypeInfo(XmlWriterDelegator writer, DataContract contract, DataContract declaredContract) + { + if (!XmlObjectSerializer.IsContractDeclared(contract, declaredContract)) + { + if (DataContractResolver == null) + { + WriteTypeInfo(writer, contract.Name, contract.Namespace); + return true; + } + else + { + WriteResolvedTypeInfo(writer, contract.OriginalUnderlyingType, declaredContract.OriginalUnderlyingType); + return false; + } + } + return false; + } + + protected virtual void WriteTypeInfo(XmlWriterDelegator writer, string dataContractName, string dataContractNamespace) + { + writer.WriteAttributeQualifiedName(Globals.XsiPrefix, DictionaryGlobals.XsiTypeLocalName, DictionaryGlobals.SchemaInstanceNamespace, dataContractName, dataContractNamespace); + } + + protected virtual void WriteTypeInfo(XmlWriterDelegator writer, XmlDictionaryString dataContractName, XmlDictionaryString dataContractNamespace) + { + writer.WriteAttributeQualifiedName(Globals.XsiPrefix, DictionaryGlobals.XsiTypeLocalName, DictionaryGlobals.SchemaInstanceNamespace, dataContractName, dataContractNamespace); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs new file mode 100644 index 0000000..fc10850 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs @@ -0,0 +1,406 @@ +using System; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Xml; +using DataContractResolver = System.Runtime.Serialization.DataContractResolver; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; +using ISurrogateSelector = System.Runtime.Serialization.ISurrogateSelector; +using SerializationBinder = System.Runtime.Serialization.SerializationBinder; +using SerializationInfo = System.Runtime.Serialization.SerializationInfo; +using StreamingContext = System.Runtime.Serialization.StreamingContext; + +namespace Compat.Runtime.Serialization +{ + internal class XmlObjectSerializerWriteContextComplex : XmlObjectSerializerWriteContext + { + protected IDataContractSurrogate dataContractSurrogate; + private readonly SerializationMode mode; + private readonly SerializationBinder binder; + private readonly ISurrogateSelector surrogateSelector; + private StreamingContext streamingContext; + private Hashtable surrogateDataContracts; + + internal XmlObjectSerializerWriteContextComplex( + DataContractSerializer serializer, + DataContract rootTypeDataContract, + DataContractResolver dataContractResolver) + : base(serializer, rootTypeDataContract, dataContractResolver) + { + mode = SerializationMode.SharedContract; + preserveObjectReferences = serializer.PreserveObjectReferences; + dataContractSurrogate = serializer.DataContractSurrogate; + } + + internal XmlObjectSerializerWriteContextComplex(NetDataContractSerializer serializer, Hashtable surrogateDataContracts) + : base(serializer) + { + mode = SerializationMode.SharedType; + preserveObjectReferences = true; + streamingContext = serializer.Context; + binder = serializer.Binder; + surrogateSelector = serializer.SurrogateSelector; + this.surrogateDataContracts = surrogateDataContracts; + } + + internal XmlObjectSerializerWriteContextComplex(XmlObjectSerializer serializer, int maxItemsInObjectGraph, StreamingContext streamingContext, bool ignoreExtensionDataObject) + : base(serializer, maxItemsInObjectGraph, streamingContext, ignoreExtensionDataObject) + { + } + + internal override SerializationMode Mode => mode; + + internal override DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = null; + if (mode == SerializationMode.SharedType && surrogateSelector != null) + { + dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, streamingContext, typeHandle, type, ref surrogateDataContracts); + } + + if (dataContract != null) + { + if (IsGetOnlyCollection && dataContract is SurrogateDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + return dataContract; + } + + return base.GetDataContract(typeHandle, type); + } + + internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle) + { + DataContract dataContract = null; + if (mode == SerializationMode.SharedType && surrogateSelector != null) + { + dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, streamingContext, typeHandle, null /*type*/, ref surrogateDataContracts); + } + + if (dataContract != null) + { + if (IsGetOnlyCollection && dataContract is SurrogateDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + return dataContract; + } + + return base.GetDataContract(id, typeHandle); + } + + internal override DataContract GetDataContractSkipValidation(int typeId, RuntimeTypeHandle typeHandle, Type type) + { + DataContract dataContract = null; + if (mode == SerializationMode.SharedType && surrogateSelector != null) + { + dataContract = NetDataContractSerializer.GetDataContractFromSurrogateSelector(surrogateSelector, streamingContext, typeHandle, null /*type*/, ref surrogateDataContracts); + } + + if (dataContract != null) + { + if (IsGetOnlyCollection && dataContract is SurrogateDataContract) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(dataContract.UnderlyingType)))); + } + return dataContract; + } + + return base.GetDataContractSkipValidation(typeId, typeHandle, type); + } + + internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, DataContract dataContract) + { + if (mode == SerializationMode.SharedType) + { + NetDataContractSerializer.WriteClrTypeInfo(xmlWriter, dataContract, binder); + return true; + } + return false; + } + + internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, string clrTypeName, string clrAssemblyName) + { + if (mode == SerializationMode.SharedType) + { + NetDataContractSerializer.WriteClrTypeInfo(xmlWriter, dataContractType, binder, clrTypeName, clrAssemblyName); + return true; + } + return false; + } + + internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, SerializationInfo serInfo) + { + if (mode == SerializationMode.SharedType) + { + NetDataContractSerializer.WriteClrTypeInfo(xmlWriter, dataContractType, binder, serInfo); + return true; + } + return false; + } + + public override void WriteAnyType(XmlWriterDelegator xmlWriter, object value) + { + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteAnyType(value); + } + } + + public override void WriteString(XmlWriterDelegator xmlWriter, string value) + { + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteString(value); + } + } + public override void WriteString(XmlWriterDelegator xmlWriter, string value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(string), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + xmlWriter.WriteStartElementPrimitive(name, ns); + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteString(value); + } + + xmlWriter.WriteEndElementPrimitive(); + } + } + + public override void WriteBase64(XmlWriterDelegator xmlWriter, byte[] value) + { + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteBase64(value); + } + } + public override void WriteBase64(XmlWriterDelegator xmlWriter, byte[] value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(byte[]), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + xmlWriter.WriteStartElementPrimitive(name, ns); + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteBase64(value); + } + + xmlWriter.WriteEndElementPrimitive(); + } + } + + public override void WriteUri(XmlWriterDelegator xmlWriter, Uri value) + { + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteUri(value); + } + } + public override void WriteUri(XmlWriterDelegator xmlWriter, Uri value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(Uri), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + xmlWriter.WriteStartElementPrimitive(name, ns); + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteUri(value); + } + + xmlWriter.WriteEndElementPrimitive(); + } + } + + public override void WriteQName(XmlWriterDelegator xmlWriter, XmlQualifiedName value) + { + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteQName(value); + } + } + public override void WriteQName(XmlWriterDelegator xmlWriter, XmlQualifiedName value, XmlDictionaryString name, XmlDictionaryString ns) + { + if (value == null) + { + WriteNull(xmlWriter, typeof(XmlQualifiedName), true/*isMemberTypeSerializable*/, name, ns); + } + else + { + if (ns != null && ns.Value != null && ns.Value.Length > 0) + { + xmlWriter.WriteStartElement(Globals.ElementPrefix, name, ns); + } + else + { + xmlWriter.WriteStartElement(name, ns); + } + + if (!OnHandleReference(xmlWriter, value, false /*canContainCyclicReference*/)) + { + xmlWriter.WriteQName(value); + } + + xmlWriter.WriteEndElement(); + } + } + + public override void InternalSerialize(XmlWriterDelegator xmlWriter, object obj, bool isDeclaredType, bool writeXsiType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle) + { + if (dataContractSurrogate == null) + { + base.InternalSerialize(xmlWriter, obj, isDeclaredType, writeXsiType, declaredTypeID, declaredTypeHandle); + } + else + { + InternalSerializeWithSurrogate(xmlWriter, obj, isDeclaredType, writeXsiType, declaredTypeID, declaredTypeHandle); + } + } + + internal override bool OnHandleReference(XmlWriterDelegator xmlWriter, object obj, bool canContainCyclicReference) + { + if (preserveObjectReferences && !IsGetOnlyCollection) + { + bool isNew = true; + int objectId = SerializedObjects.GetId(obj, ref isNew); + if (isNew) + { + xmlWriter.WriteAttributeInt(Globals.SerPrefix, DictionaryGlobals.IdLocalName, DictionaryGlobals.SerializationNamespace, objectId); + } + else + { + xmlWriter.WriteAttributeInt(Globals.SerPrefix, DictionaryGlobals.RefLocalName, DictionaryGlobals.SerializationNamespace, objectId); + xmlWriter.WriteAttributeBool(Globals.XsiPrefix, DictionaryGlobals.XsiNilLocalName, DictionaryGlobals.SchemaInstanceNamespace, true); + } + return !isNew; + } + return base.OnHandleReference(xmlWriter, obj, canContainCyclicReference); + } + + internal override void OnEndHandleReference(XmlWriterDelegator xmlWriter, object obj, bool canContainCyclicReference) + { + if (preserveObjectReferences && !IsGetOnlyCollection) + { + return; + } + + base.OnEndHandleReference(xmlWriter, obj, canContainCyclicReference); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private bool CheckIfTypeSerializableForSharedTypeMode(Type memberType) + { + Fx.Assert(surrogateSelector != null, "Method should not be called when surrogateSelector is null."); + return (surrogateSelector.GetSurrogate(memberType, streamingContext, out ISurrogateSelector surrogateSelectorNotUsed) != null); + } + + internal override void CheckIfTypeSerializable(Type memberType, bool isMemberTypeSerializable) + { + if (mode == SerializationMode.SharedType && surrogateSelector != null && + CheckIfTypeSerializableForSharedTypeMode(memberType)) + { + return; + } + else + { + if (dataContractSurrogate != null) + { + while (memberType.IsArray) + { + memberType = memberType.GetElementType(); + } + + memberType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, memberType); + if (!DataContract.IsTypeSerializable(memberType)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeNotSerializable, memberType))); + } + + return; + } + } + + base.CheckIfTypeSerializable(memberType, isMemberTypeSerializable); + } + + internal override Type GetSurrogatedType(Type type) + { + if (dataContractSurrogate == null) + { + return base.GetSurrogatedType(type); + } + else + { + type = DataContract.UnwrapNullableType(type); + Type surrogateType = DataContractSerializer.GetSurrogatedType(dataContractSurrogate, type); + if (IsGetOnlyCollection && surrogateType != type) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser, + DataContract.GetClrTypeFullName(type)))); + } + else + { + return surrogateType; + } + } + } + + private void InternalSerializeWithSurrogate(XmlWriterDelegator xmlWriter, object obj, bool isDeclaredType, bool writeXsiType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle) + { + RuntimeTypeHandle objTypeHandle = isDeclaredType ? declaredTypeHandle : Type.GetTypeHandle(obj); + object oldObj = obj; + int objOldId = 0; + Type objType = Type.GetTypeFromHandle(objTypeHandle); + Type declaredType = GetSurrogatedType(Type.GetTypeFromHandle(declaredTypeHandle)); + + declaredTypeHandle = declaredType.TypeHandle; + obj = DataContractSerializer.SurrogateToDataContractType(dataContractSurrogate, obj, declaredType, ref objType); + objTypeHandle = objType.TypeHandle; + if (oldObj != obj) + { + objOldId = SerializedObjects.ReassignId(0, oldObj, obj); + } + + if (writeXsiType) + { + declaredType = Globals.TypeOfObject; + SerializeWithXsiType(xmlWriter, obj, objTypeHandle, objType, -1, declaredType.TypeHandle, declaredType); + } + else if (declaredTypeHandle.Equals(objTypeHandle)) + { + DataContract contract = GetDataContract(objTypeHandle, objType); + SerializeWithoutXsiType(contract, xmlWriter, obj, declaredTypeHandle); + } + else + { + SerializeWithXsiType(xmlWriter, obj, objTypeHandle, objType, -1, declaredTypeHandle, declaredType); + } + if (oldObj != obj) + { + SerializedObjects.ReassignId(objOldId, obj, oldObj); + } + } + + internal override void WriteArraySize(XmlWriterDelegator xmlWriter, int size) + { + if (preserveObjectReferences && size > -1) + { + xmlWriter.WriteAttributeInt(Globals.SerPrefix, DictionaryGlobals.ArraySizeLocalName, DictionaryGlobals.SerializationNamespace, size); + } + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlReaderDelegator.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlReaderDelegator.cs new file mode 100644 index 0000000..9ac6adb --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlReaderDelegator.cs @@ -0,0 +1,1224 @@ +using Compat.Xml; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; +using System.Xml.Serialization; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; + +namespace Compat.Runtime.Serialization +{ + internal class XmlReaderDelegator + { + private readonly XmlReader _reader; + private readonly XmlDictionaryReader _dictionaryReader; + private bool _isEndOfEmptyElement = false; + + public XmlReaderDelegator(XmlReader reader) + { + _reader = reader ?? throw new ArgumentNullException(nameof(reader)); + _dictionaryReader = reader as XmlDictionaryReader; + } + + internal XmlReader UnderlyingReader => _reader; + + internal ExtensionDataReader UnderlyingExtensionDataReader => _reader as ExtensionDataReader; + + internal int AttributeCount => _isEndOfEmptyElement ? 0 : _reader.AttributeCount; + + internal string GetAttribute(string name) + { + return _isEndOfEmptyElement ? null : _reader.GetAttribute(name); + } + + internal string GetAttribute(string name, string namespaceUri) + { + return _isEndOfEmptyElement ? null : _reader.GetAttribute(name, namespaceUri); + } + + internal string GetAttribute(int i) + { + if (_isEndOfEmptyElement) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(i), SR.XmlElementAttributes)); + } + + return _reader.GetAttribute(i); + } + + internal bool IsEmptyElement => false; + + internal bool IsNamespaceURI(string ns) + { + if (_dictionaryReader == null) + { + return ns == _reader.NamespaceURI; + } + else + { + return _dictionaryReader.IsNamespaceUri(ns); + } + } + + internal bool IsLocalName(string localName) + { + if (_dictionaryReader == null) + { + return localName == _reader.LocalName; + } + else + { + return _dictionaryReader.IsLocalName(localName); + } + } + + internal bool IsNamespaceUri(XmlDictionaryString ns) + { + if (_dictionaryReader == null) + { + return ns.Value == _reader.NamespaceURI; + } + else + { + return _dictionaryReader.IsNamespaceUri(ns); + } + } + + internal bool IsLocalName(XmlDictionaryString localName) + { + if (_dictionaryReader == null) + { + return localName.Value == _reader.LocalName; + } + else + { + return _dictionaryReader.IsLocalName(localName); + } + } + + internal int IndexOfLocalName(XmlDictionaryString[] localNames, XmlDictionaryString ns) + { + if (_dictionaryReader != null) + { + return _dictionaryReader.IndexOfLocalName(localNames, ns); + } + + if (_reader.NamespaceURI == ns.Value) + { + string localName = LocalName; + for (int i = 0; i < localNames.Length; i++) + { + if (localName == localNames[i].Value) + { + return i; + } + } + } + + return -1; + } + + public bool IsStartElement() + { + return !_isEndOfEmptyElement && _reader.IsStartElement(); + } + + internal bool IsStartElement(string localname, string ns) + { + return !_isEndOfEmptyElement && _reader.IsStartElement(localname, ns); + } + + public bool IsStartElement(XmlDictionaryString localname, XmlDictionaryString ns) + { + if (_dictionaryReader == null) + { + return !_isEndOfEmptyElement && _reader.IsStartElement(localname.Value, ns.Value); + } + else + { + return !_isEndOfEmptyElement && _dictionaryReader.IsStartElement(localname, ns); + } + } + + internal bool MoveToAttribute(string name) + { + return _isEndOfEmptyElement ? false : _reader.MoveToAttribute(name); + } + + internal bool MoveToAttribute(string name, string ns) + { + return _isEndOfEmptyElement ? false : _reader.MoveToAttribute(name, ns); + } + + internal void MoveToAttribute(int i) + { + if (_isEndOfEmptyElement) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(i), SR.XmlElementAttributes)); + } + + _reader.MoveToAttribute(i); + } + + internal bool MoveToElement() + { + return _isEndOfEmptyElement ? false : _reader.MoveToElement(); + } + + internal bool MoveToFirstAttribute() + { + return _isEndOfEmptyElement ? false : _reader.MoveToFirstAttribute(); + } + + internal bool MoveToNextAttribute() + { + return _isEndOfEmptyElement ? false : _reader.MoveToNextAttribute(); + } + + public XmlNodeType NodeType => _isEndOfEmptyElement ? XmlNodeType.EndElement : _reader.NodeType; + + internal bool Read() + { + _reader.MoveToElement(); + if (!_reader.IsEmptyElement) + { + return _reader.Read(); + } + + if (_isEndOfEmptyElement) + { + _isEndOfEmptyElement = false; + return _reader.Read(); + } + _isEndOfEmptyElement = true; + return true; + } + + internal XmlNodeType MoveToContent() + { + if (_isEndOfEmptyElement) + { + return XmlNodeType.EndElement; + } + + return _reader.MoveToContent(); + } + + internal bool ReadAttributeValue() + { + return _isEndOfEmptyElement ? false : _reader.ReadAttributeValue(); + } + + public void ReadEndElement() + { + if (_isEndOfEmptyElement) + { + Read(); + } + else + { + _reader.ReadEndElement(); + } + } + + private Exception CreateInvalidPrimitiveTypeException(Type type) + { + return new InvalidDataContractException(SR.Format( + type.IsInterface ? SR.InterfaceTypeCannotBeCreated : SR.InvalidPrimitiveType, + DataContract.GetClrTypeFullName(type))); + } + + public object ReadElementContentAsAnyType(Type valueType) + { + Read(); + object o = ReadContentAsAnyType(valueType); + ReadEndElement(); + return o; + } + + internal object ReadContentAsAnyType(Type valueType) + { + switch (Type.GetTypeCode(valueType)) + { + case TypeCode.Boolean: + return ReadContentAsBoolean(); + case TypeCode.Char: + return ReadContentAsChar(); + case TypeCode.Byte: + return ReadContentAsUnsignedByte(); + case TypeCode.Int16: + return ReadContentAsShort(); + case TypeCode.Int32: + return ReadContentAsInt(); + case TypeCode.Int64: + return ReadContentAsLong(); + case TypeCode.Single: + return ReadContentAsSingle(); + case TypeCode.Double: + return ReadContentAsDouble(); + case TypeCode.Decimal: + return ReadContentAsDecimal(); + case TypeCode.DateTime: + return ReadContentAsDateTime(); + case TypeCode.String: + return ReadContentAsString(); + + case TypeCode.SByte: + return ReadContentAsSignedByte(); + case TypeCode.UInt16: + return ReadContentAsUnsignedShort(); + case TypeCode.UInt32: + return ReadContentAsUnsignedInt(); + case TypeCode.UInt64: + return ReadContentAsUnsignedLong(); + case TypeCode.Empty: + case TypeCode.DBNull: + case TypeCode.Object: + default: + if (valueType == Globals.TypeOfByteArray) + { + return ReadContentAsBase64(); + } + else if (valueType == Globals.TypeOfObject) + { + return new object(); + } + else if (valueType == Globals.TypeOfTimeSpan) + { + return ReadContentAsTimeSpan(); + } + else if (valueType == Globals.TypeOfGuid) + { + return ReadContentAsGuid(); + } + else if (valueType == Globals.TypeOfUri) + { + return ReadContentAsUri(); + } + else if (valueType == Globals.TypeOfXmlQualifiedName) + { + return ReadContentAsQName(); + } + + break; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidPrimitiveTypeException(valueType)); + } + + internal IDataNode ReadExtensionData(Type valueType) + { + switch (Type.GetTypeCode(valueType)) + { + case TypeCode.Boolean: + return new DataNode(ReadContentAsBoolean()); + case TypeCode.Char: + return new DataNode(ReadContentAsChar()); + case TypeCode.Byte: + return new DataNode(ReadContentAsUnsignedByte()); + case TypeCode.Int16: + return new DataNode(ReadContentAsShort()); + case TypeCode.Int32: + return new DataNode(ReadContentAsInt()); + case TypeCode.Int64: + return new DataNode(ReadContentAsLong()); + case TypeCode.Single: + return new DataNode(ReadContentAsSingle()); + case TypeCode.Double: + return new DataNode(ReadContentAsDouble()); + case TypeCode.Decimal: + return new DataNode(ReadContentAsDecimal()); + case TypeCode.DateTime: + return new DataNode(ReadContentAsDateTime()); + case TypeCode.String: + return new DataNode(ReadContentAsString()); + case TypeCode.SByte: + return new DataNode(ReadContentAsSignedByte()); + case TypeCode.UInt16: + return new DataNode(ReadContentAsUnsignedShort()); + case TypeCode.UInt32: + return new DataNode(ReadContentAsUnsignedInt()); + case TypeCode.UInt64: + return new DataNode(ReadContentAsUnsignedLong()); + case TypeCode.Empty: + case TypeCode.DBNull: + case TypeCode.Object: + default: + if (valueType == Globals.TypeOfByteArray) + { + return new DataNode(ReadContentAsBase64()); + } + else if (valueType == Globals.TypeOfObject) + { + return new DataNode(new object()); + } + else if (valueType == Globals.TypeOfTimeSpan) + { + return new DataNode(ReadContentAsTimeSpan()); + } + else if (valueType == Globals.TypeOfGuid) + { + return new DataNode(ReadContentAsGuid()); + } + else if (valueType == Globals.TypeOfUri) + { + return new DataNode(ReadContentAsUri()); + } + else if (valueType == Globals.TypeOfXmlQualifiedName) + { + return new DataNode(ReadContentAsQName()); + } + + break; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidPrimitiveTypeException(valueType)); + } + + private void ThrowConversionException(string value, string type) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(XmlObjectSerializer.TryAddLineInfo(this, SR.Format(SR.XmlInvalidConversion, value, type)))); + } + + private void ThrowNotAtElement() + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.XmlStartElementExpected, "EndElement"))); + } + + internal virtual char ReadElementContentAsChar() + { + return ToChar(ReadElementContentAsInt()); + } + + internal virtual char ReadContentAsChar() + { + return ToChar(ReadContentAsInt()); + } + + private char ToChar(int value) + { + if (value < char.MinValue || value > char.MaxValue) + { + ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Char"); + } + return (char)value; + } + + public string ReadElementContentAsString() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsString(); + } + + internal string ReadContentAsString() + { + return _isEndOfEmptyElement ? string.Empty : _reader.ReadContentAsString(); + } + + public bool ReadElementContentAsBoolean() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsBoolean(); + } + + internal bool ReadContentAsBoolean() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "Boolean"); + } + + return _reader.ReadContentAsBoolean(); + } + + public float ReadElementContentAsFloat() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsFloat(); + } + + internal float ReadContentAsSingle() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "Float"); + } + + return _reader.ReadContentAsFloat(); + } + + public double ReadElementContentAsDouble() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsDouble(); + } + + internal double ReadContentAsDouble() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "Double"); + } + + return _reader.ReadContentAsDouble(); + } + + public decimal ReadElementContentAsDecimal() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsDecimal(); + } + + internal decimal ReadContentAsDecimal() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "Decimal"); + } + + return _reader.ReadContentAsDecimal(); + } + + internal virtual byte[] ReadElementContentAsBase64() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + if (_dictionaryReader == null) + { + return ReadContentAsBase64(_reader.ReadElementContentAsString()); + } + else + { + return _dictionaryReader.ReadElementContentAsBase64(); + } + } + + internal virtual byte[] ReadContentAsBase64() + { + if (_isEndOfEmptyElement) + { + return new byte[0]; + } + + if (_dictionaryReader == null) + { + return ReadContentAsBase64(_reader.ReadContentAsString()); + } + else + { + return _dictionaryReader.ReadContentAsBase64(); + } + } + + internal byte[] ReadContentAsBase64(string str) + { + if (str == null) + { + return null; + } + + str = str.Trim(); + if (str.Length == 0) + { + return new byte[0]; + } + + try + { + return Convert.FromBase64String(str); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "byte[]", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "byte[]", exception)); + } + } + + internal virtual DateTime ReadElementContentAsDateTime() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsDateTime(); + } + + internal virtual DateTime ReadContentAsDateTime() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "DateTime"); + } + + return _reader.ReadContentAsDateTime(); + } + + public int ReadElementContentAsInt() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsInt(); + } + + internal int ReadContentAsInt() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "Int32"); + } + + return _reader.ReadContentAsInt(); + } + + public long ReadElementContentAsLong() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + return _reader.ReadElementContentAsLong(); + } + + internal long ReadContentAsLong() + { + if (_isEndOfEmptyElement) + { + ThrowConversionException(string.Empty, "Int64"); + } + + return _reader.ReadContentAsLong(); + } + + public short ReadElementContentAsShort() + { + return ToShort(ReadElementContentAsInt()); + } + + internal short ReadContentAsShort() + { + return ToShort(ReadContentAsInt()); + } + + private short ToShort(int value) + { + if (value < short.MinValue || value > short.MaxValue) + { + ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Int16"); + } + return (short)value; + } + + public byte ReadElementContentAsUnsignedByte() + { + return ToByte(ReadElementContentAsInt()); + } + + internal byte ReadContentAsUnsignedByte() + { + return ToByte(ReadContentAsInt()); + } + + private byte ToByte(int value) + { + if (value < byte.MinValue || value > byte.MaxValue) + { + ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "Byte"); + } + return (byte)value; + } + + public sbyte ReadElementContentAsSignedByte() + { + return ToSByte(ReadElementContentAsInt()); + } + + internal sbyte ReadContentAsSignedByte() + { + return ToSByte(ReadContentAsInt()); + } + + private sbyte ToSByte(int value) + { + if (value < sbyte.MinValue || value > sbyte.MaxValue) + { + ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "SByte"); + } + return (sbyte)value; + } + + public uint ReadElementContentAsUnsignedInt() + { + return ToUInt32(ReadElementContentAsLong()); + } + + internal uint ReadContentAsUnsignedInt() + { + return ToUInt32(ReadContentAsLong()); + } + + private uint ToUInt32(long value) + { + if (value < uint.MinValue || value > uint.MaxValue) + { + ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "UInt32"); + } + return (uint)value; + } + + internal virtual ulong ReadElementContentAsUnsignedLong() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + string str = _reader.ReadElementContentAsString(); + + if (str == null || str.Length == 0) + { + ThrowConversionException(string.Empty, "UInt64"); + } + + return XmlConverter.ToUInt64(str); + } + + internal virtual ulong ReadContentAsUnsignedLong() + { + string str = _reader.ReadContentAsString(); + + if (str == null || str.Length == 0) + { + ThrowConversionException(string.Empty, "UInt64"); + } + + return XmlConverter.ToUInt64(str); + } + + public ushort ReadElementContentAsUnsignedShort() + { + return ToUInt16(ReadElementContentAsInt()); + } + + internal ushort ReadContentAsUnsignedShort() + { + return ToUInt16(ReadContentAsInt()); + } + + private ushort ToUInt16(int value) + { + if (value < ushort.MinValue || value > ushort.MaxValue) + { + ThrowConversionException(value.ToString(NumberFormatInfo.CurrentInfo), "UInt16"); + } + return (ushort)value; + } + + public TimeSpan ReadElementContentAsTimeSpan() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + string str = _reader.ReadElementContentAsString(); + return XmlConverter.ToTimeSpan(str); + } + + internal TimeSpan ReadContentAsTimeSpan() + { + string str = _reader.ReadContentAsString(); + return XmlConverter.ToTimeSpan(str); + } + + public Guid ReadElementContentAsGuid() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + string str = _reader.ReadElementContentAsString(); + try + { + return Guid.Parse(str); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception)); + } + } + + internal Guid ReadContentAsGuid() + { + string str = _reader.ReadContentAsString(); + try + { + return Guid.Parse(str); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception)); + } + catch (OverflowException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Guid", exception)); + } + } + + public Uri ReadElementContentAsUri() + { + if (_isEndOfEmptyElement) + { + ThrowNotAtElement(); + } + + string str = ReadElementContentAsString(); + try + { + return new Uri(str, UriKind.RelativeOrAbsolute); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception)); + } + } + + internal Uri ReadContentAsUri() + { + string str = ReadContentAsString(); + try + { + return new Uri(str, UriKind.RelativeOrAbsolute); + } + catch (ArgumentException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception)); + } + catch (FormatException exception) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(str, "Uri", exception)); + } + } + + public XmlQualifiedName ReadElementContentAsQName() + { + Read(); + XmlQualifiedName obj = ReadContentAsQName(); + ReadEndElement(); + return obj; + } + + internal virtual XmlQualifiedName ReadContentAsQName() + { + return ParseQualifiedName(ReadContentAsString()); + } + + private XmlQualifiedName ParseQualifiedName(string str) + { + string name, ns; + if (str == null || str.Length == 0) + { + name = ns = string.Empty; + } + else + { + XmlObjectSerializerReadContext.ParseQualifiedName(str, this, out name, out ns, out string prefix); + } + + return new XmlQualifiedName(name, ns); + } + + private void CheckExpectedArrayLength(XmlObjectSerializerReadContext context, int arrayLength) + { + context.IncrementItemCount(arrayLength); + } + + protected int GetArrayLengthQuota(XmlObjectSerializerReadContext context) + { + if (_dictionaryReader.Quotas == null) + { + return context.RemainingItemCount; + } + + return Math.Min(context.RemainingItemCount, _dictionaryReader.Quotas.MaxArrayLength); + } + + private void CheckActualArrayLength(int expectedLength, int actualLength, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (expectedLength != actualLength) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayExceededSizeAttribute, expectedLength, itemName.Value, itemNamespace.Value))); + } + } + + internal bool TryReadBooleanArray(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out bool[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new bool[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = BooleanArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal bool TryReadDateTimeArray(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out DateTime[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new DateTime[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = DateTimeArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal bool TryReadDecimalArray(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out decimal[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new decimal[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = DecimalArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal bool TryReadInt32Array(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out int[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new int[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = Int32ArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal bool TryReadInt64Array(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out long[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new long[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = Int64ArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal bool TryReadSingleArray(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out float[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new float[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = SingleArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal bool TryReadDoubleArray(XmlObjectSerializerReadContext context, + XmlDictionaryString itemName, XmlDictionaryString itemNamespace, + int arrayLength, out double[] array) + { + if (_dictionaryReader == null) + { + array = null; + return false; + } + + if (arrayLength != -1) + { + CheckExpectedArrayLength(context, arrayLength); + array = new double[arrayLength]; + int read = 0, offset = 0; + while ((read = _dictionaryReader.ReadArray(itemName, itemNamespace, array, offset, arrayLength - offset)) > 0) + { + offset += read; + } + CheckActualArrayLength(arrayLength, offset, itemName, itemNamespace); + } + else + { + array = DoubleArrayHelperWithDictionaryString.Instance.ReadArray( + _dictionaryReader, itemName, itemNamespace, GetArrayLengthQuota(context)); + context.IncrementItemCount(array.Length); + } + return true; + } + + internal IDictionary GetNamespacesInScope(XmlNamespaceScope scope) + { + return (_reader is IXmlNamespaceResolver) ? ((IXmlNamespaceResolver)_reader).GetNamespacesInScope(scope) : null; + } + + // IXmlLineInfo members + internal bool HasLineInfo() + { + IXmlLineInfo iXmlLineInfo = _reader as IXmlLineInfo; + return (iXmlLineInfo == null) ? false : iXmlLineInfo.HasLineInfo(); + } + + internal int LineNumber + { + get + { + IXmlLineInfo iXmlLineInfo = _reader as IXmlLineInfo; + return (iXmlLineInfo == null) ? 0 : iXmlLineInfo.LineNumber; + } + } + + internal int LinePosition + { + get + { + IXmlLineInfo iXmlLineInfo = _reader as IXmlLineInfo; + return (iXmlLineInfo == null) ? 0 : iXmlLineInfo.LinePosition; + } + } + + // IXmlTextParser members + internal bool Normalized + { + get + { + XmlTextReader xmlTextReader = _reader as XmlTextReader; + if (xmlTextReader == null) + { + IXmlTextParser xmlTextParser = _reader as IXmlTextParser; + return (xmlTextParser == null) ? false : xmlTextParser.Normalized; + } + else + { + return xmlTextReader.Normalization; + } + } + set + { + XmlTextReader xmlTextReader = _reader as XmlTextReader; + if (xmlTextReader == null) + { + IXmlTextParser xmlTextParser = _reader as IXmlTextParser; + if (xmlTextParser != null) + { + xmlTextParser.Normalized = value; + } + } + else + { + xmlTextReader.Normalization = value; + } + } + } + + internal WhitespaceHandling WhitespaceHandling + { + get + { + XmlTextReader xmlTextReader = _reader as XmlTextReader; + if (xmlTextReader == null) + { + IXmlTextParser xmlTextParser = _reader as IXmlTextParser; + return (xmlTextParser == null) ? WhitespaceHandling.None : xmlTextParser.WhitespaceHandling; + } + else + { + return xmlTextReader.WhitespaceHandling; + } + } + set + { + XmlTextReader xmlTextReader = _reader as XmlTextReader; + if (xmlTextReader == null) + { + IXmlTextParser xmlTextParser = _reader as IXmlTextParser; + if (xmlTextParser != null) + { + xmlTextParser.WhitespaceHandling = value; + } + } + else + { + xmlTextReader.WhitespaceHandling = value; + } + } + } + + // delegating properties and methods + internal string Name => _reader.Name; + + public string LocalName => _reader.LocalName; + + internal string NamespaceURI => _reader.NamespaceURI; + internal string Value => _reader.Value; + internal Type ValueType => _reader.ValueType; + internal int Depth => _reader.Depth; + internal string LookupNamespace(string prefix) { return _reader.LookupNamespace(prefix); } + internal bool EOF => _reader.EOF; + + internal void Skip() + { + _reader.Skip(); + _isEndOfEmptyElement = false; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableReader.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableReader.cs new file mode 100644 index 0000000..f3f9fc4 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableReader.cs @@ -0,0 +1,199 @@ +using System; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace Compat.Runtime.Serialization +{ + internal class XmlSerializableReader : XmlReader, IXmlLineInfo, IXmlTextParser + { + private XmlReaderDelegator xmlReader; + private int startDepth; + private bool isRootEmptyElement; + private XmlReader innerReader; + + private XmlReader InnerReader => innerReader; + + internal void BeginRead(XmlReaderDelegator xmlReader) + { + if (xmlReader.NodeType != XmlNodeType.Element) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializerReadContext.CreateUnexpectedStateException(XmlNodeType.Element, xmlReader)); + } + + this.xmlReader = xmlReader; + startDepth = xmlReader.Depth; + innerReader = xmlReader.UnderlyingReader; + isRootEmptyElement = InnerReader.IsEmptyElement; + } + + internal void EndRead() + { + if (isRootEmptyElement) + { + xmlReader.Read(); + } + else + { + if (xmlReader.IsStartElement() && xmlReader.Depth == startDepth) + { + xmlReader.Read(); + } + + while (xmlReader.Depth > startDepth) + { + if (!xmlReader.Read()) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializerReadContext.CreateUnexpectedStateException(XmlNodeType.EndElement, xmlReader)); + } + } + } + } + + public override bool Read() + { + XmlReader reader = InnerReader; + if (reader.Depth == startDepth) + { + if (reader.NodeType == XmlNodeType.EndElement || + (reader.NodeType == XmlNodeType.Element && reader.IsEmptyElement)) + { + return false; + } + } + return reader.Read(); + } + + public override void Close() + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.IXmlSerializableIllegalOperation)); + } + + public override XmlReaderSettings Settings => InnerReader.Settings; + public override XmlNodeType NodeType => InnerReader.NodeType; + public override string Name => InnerReader.Name; + public override string LocalName => InnerReader.LocalName; + public override string NamespaceURI => InnerReader.NamespaceURI; + public override string Prefix => InnerReader.Prefix; + public override bool HasValue => InnerReader.HasValue; + public override string Value => InnerReader.Value; + public override int Depth => InnerReader.Depth; + public override string BaseURI => InnerReader.BaseURI; + public override bool IsEmptyElement => InnerReader.IsEmptyElement; + public override bool IsDefault => InnerReader.IsDefault; + public override char QuoteChar => InnerReader.QuoteChar; + public override XmlSpace XmlSpace => InnerReader.XmlSpace; + public override string XmlLang => InnerReader.XmlLang; + public override IXmlSchemaInfo SchemaInfo => InnerReader.SchemaInfo; + public override Type ValueType => InnerReader.ValueType; + public override int AttributeCount => InnerReader.AttributeCount; + public override string this[int i] => InnerReader[i]; + public override string this[string name] => InnerReader[name]; + public override string this[string name, string namespaceURI] => InnerReader[name, namespaceURI]; + public override bool EOF => InnerReader.EOF; + public override ReadState ReadState => InnerReader.ReadState; + public override XmlNameTable NameTable => InnerReader.NameTable; + public override bool CanResolveEntity => InnerReader.CanResolveEntity; + public override bool CanReadBinaryContent => InnerReader.CanReadBinaryContent; + public override bool CanReadValueChunk => InnerReader.CanReadValueChunk; + public override bool HasAttributes => InnerReader.HasAttributes; + + public override string GetAttribute(string name) { return InnerReader.GetAttribute(name); } + public override string GetAttribute(string name, string namespaceURI) { return InnerReader.GetAttribute(name, namespaceURI); } + public override string GetAttribute(int i) { return InnerReader.GetAttribute(i); } + public override bool MoveToAttribute(string name) { return InnerReader.MoveToAttribute(name); } + public override bool MoveToAttribute(string name, string ns) { return InnerReader.MoveToAttribute(name, ns); } + public override void MoveToAttribute(int i) { InnerReader.MoveToAttribute(i); } + public override bool MoveToFirstAttribute() { return InnerReader.MoveToFirstAttribute(); } + public override bool MoveToNextAttribute() { return InnerReader.MoveToNextAttribute(); } + public override bool MoveToElement() { return InnerReader.MoveToElement(); } + public override string LookupNamespace(string prefix) { return InnerReader.LookupNamespace(prefix); } + public override bool ReadAttributeValue() { return InnerReader.ReadAttributeValue(); } + public override void ResolveEntity() { InnerReader.ResolveEntity(); } + public override bool IsStartElement() { return InnerReader.IsStartElement(); } + public override bool IsStartElement(string name) { return InnerReader.IsStartElement(name); } + public override bool IsStartElement(string localname, string ns) { return InnerReader.IsStartElement(localname, ns); } + public override XmlNodeType MoveToContent() { return InnerReader.MoveToContent(); } + + public override object ReadContentAsObject() { return InnerReader.ReadContentAsObject(); } + public override bool ReadContentAsBoolean() { return InnerReader.ReadContentAsBoolean(); } + public override DateTime ReadContentAsDateTime() { return InnerReader.ReadContentAsDateTime(); } + public override double ReadContentAsDouble() { return InnerReader.ReadContentAsDouble(); } + public override int ReadContentAsInt() { return InnerReader.ReadContentAsInt(); } + public override long ReadContentAsLong() { return InnerReader.ReadContentAsLong(); } + public override string ReadContentAsString() { return InnerReader.ReadContentAsString(); } + public override object ReadContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver) { return InnerReader.ReadContentAs(returnType, namespaceResolver); } + public override int ReadContentAsBase64(byte[] buffer, int index, int count) { return InnerReader.ReadContentAsBase64(buffer, index, count); } + public override int ReadContentAsBinHex(byte[] buffer, int index, int count) { return InnerReader.ReadContentAsBinHex(buffer, index, count); } + public override int ReadValueChunk(char[] buffer, int index, int count) { return InnerReader.ReadValueChunk(buffer, index, count); } + public override string ReadString() { return InnerReader.ReadString(); } + + // IXmlTextParser members + bool IXmlTextParser.Normalized + { + get + { + IXmlTextParser xmlTextParser = InnerReader as IXmlTextParser; + return (xmlTextParser == null) ? xmlReader.Normalized : xmlTextParser.Normalized; + } + set + { + IXmlTextParser xmlTextParser = InnerReader as IXmlTextParser; + if (xmlTextParser == null) + { + xmlReader.Normalized = value; + } + else + { + xmlTextParser.Normalized = value; + } + } + } + + WhitespaceHandling IXmlTextParser.WhitespaceHandling + { + get + { + IXmlTextParser xmlTextParser = InnerReader as IXmlTextParser; + return (xmlTextParser == null) ? xmlReader.WhitespaceHandling : xmlTextParser.WhitespaceHandling; + } + set + { + IXmlTextParser xmlTextParser = InnerReader as IXmlTextParser; + if (xmlTextParser == null) + { + xmlReader.WhitespaceHandling = value; + } + else + { + xmlTextParser.WhitespaceHandling = value; + } + } + } + + // IXmlLineInfo members + bool IXmlLineInfo.HasLineInfo() + { + IXmlLineInfo xmlLineInfo = InnerReader as IXmlLineInfo; + return (xmlLineInfo == null) ? xmlReader.HasLineInfo() : xmlLineInfo.HasLineInfo(); + } + + int IXmlLineInfo.LineNumber + { + get + { + IXmlLineInfo xmlLineInfo = InnerReader as IXmlLineInfo; + return (xmlLineInfo == null) ? xmlReader.LineNumber : xmlLineInfo.LineNumber; + } + } + + int IXmlLineInfo.LinePosition + { + get + { + IXmlLineInfo xmlLineInfo = InnerReader as IXmlLineInfo; + return (xmlLineInfo == null) ? xmlReader.LinePosition : xmlLineInfo.LinePosition; + } + } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableWriter.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableWriter.cs new file mode 100644 index 0000000..bc2f09a --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlSerializableWriter.cs @@ -0,0 +1,109 @@ +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal class XmlSerializableWriter : XmlWriter + { + private XmlWriter _xmlWriter; + private int _depth = 0; + private object _obj; + + internal void BeginWrite(XmlWriter xmlWriter, object obj) + { + _depth = 0; + _xmlWriter = xmlWriter; + _obj = obj; + } + + internal void EndWrite() + { + if (_depth != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IXmlSerializableMissingEndElements, (_obj == null ? string.Empty : DataContract.GetClrTypeFullName(_obj.GetType()))))); + } + + _obj = null; + } + + public override void WriteStartDocument() + { + if (WriteState == WriteState.Start) + { + _xmlWriter.WriteStartDocument(); + } + } + public override void WriteEndDocument() { _xmlWriter.WriteEndDocument(); } + public override void WriteStartDocument(bool standalone) + { + if (WriteState == WriteState.Start) + { + _xmlWriter.WriteStartDocument(standalone); + } + } + public override void WriteDocType(string name, string pubid, string sysid, string subset) + { + // XmlSerializer does not write doc type + } + + public override void WriteStartElement(string prefix, string localName, string ns) + { + _xmlWriter.WriteStartElement(prefix, localName, ns); + _depth++; + } + + public override void WriteEndElement() + { + if (_depth == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IXmlSerializableWritePastSubTree, (_obj == null ? string.Empty : DataContract.GetClrTypeFullName(_obj.GetType()))))); + } + + _xmlWriter.WriteEndElement(); + _depth--; + } + + public override void WriteFullEndElement() + { + if (_depth == 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.IXmlSerializableWritePastSubTree, (_obj == null ? string.Empty : DataContract.GetClrTypeFullName(_obj.GetType()))))); + } + + _xmlWriter.WriteFullEndElement(); + _depth--; + } + + public override void Close() + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.IXmlSerializableIllegalOperation)); + } + + public override void WriteStartAttribute(string prefix, string localName, string ns) + { + _xmlWriter.WriteStartAttribute(prefix, localName, ns); + } + + public override void WriteEndAttribute() { _xmlWriter.WriteEndAttribute(); } + public override void WriteCData(string text) { _xmlWriter.WriteCData(text); } + public override void WriteComment(string text) { _xmlWriter.WriteComment(text); } + public override void WriteProcessingInstruction(string name, string text) { _xmlWriter.WriteProcessingInstruction(name, text); } + public override void WriteEntityRef(string name) { _xmlWriter.WriteEntityRef(name); } + public override void WriteCharEntity(char ch) { _xmlWriter.WriteCharEntity(ch); } + public override void WriteWhitespace(string ws) { _xmlWriter.WriteWhitespace(ws); } + public override void WriteString(string text) { _xmlWriter.WriteString(text); } + public override void WriteSurrogateCharEntity(char lowChar, char highChar) { _xmlWriter.WriteSurrogateCharEntity(lowChar, highChar); } + public override void WriteChars(char[] buffer, int index, int count) { _xmlWriter.WriteChars(buffer, index, count); } + public override void WriteRaw(char[] buffer, int index, int count) { _xmlWriter.WriteRaw(buffer, index, count); } + public override void WriteRaw(string data) { _xmlWriter.WriteRaw(data); } + public override void WriteBase64(byte[] buffer, int index, int count) { _xmlWriter.WriteBase64(buffer, index, count); } + public override void WriteBinHex(byte[] buffer, int index, int count) { _xmlWriter.WriteBinHex(buffer, index, count); } + public override WriteState WriteState => _xmlWriter.WriteState; + public override void Flush() { _xmlWriter.Flush(); } + public override void WriteName(string name) { _xmlWriter.WriteName(name); } + public override void WriteQualifiedName(string localName, string ns) { _xmlWriter.WriteQualifiedName(localName, ns); } + public override string LookupPrefix(string ns) { return _xmlWriter.LookupPrefix(ns); } + public override XmlSpace XmlSpace => _xmlWriter.XmlSpace; + public override string XmlLang => _xmlWriter.XmlLang; + public override void WriteNmToken(string name) { _xmlWriter.WriteNmToken(name); } + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlWriterDelegator.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlWriterDelegator.cs new file mode 100644 index 0000000..d96a19c --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XmlWriterDelegator.cs @@ -0,0 +1,812 @@ +using System; +using System.Globalization; +using System.Xml; + +namespace Compat.Runtime.Serialization +{ + internal class XmlWriterDelegator + { + protected XmlWriter _writer; + protected XmlDictionaryWriter _dictionaryWriter; + internal int _depth; + private int _prefixes; + + public XmlWriterDelegator(XmlWriter writer) + { + _writer = writer ?? throw new ArgumentNullException(nameof(writer)); + _dictionaryWriter = writer as XmlDictionaryWriter; + } + + internal XmlWriter Writer => _writer; + + internal void Flush() + { + _writer.Flush(); + } + + internal string LookupPrefix(string ns) + { + return _writer.LookupPrefix(ns); + } + + private void WriteEndAttribute() + { + _writer.WriteEndAttribute(); + } + + public void WriteEndElement() + { + _writer.WriteEndElement(); + _depth--; + } + + internal void WriteRaw(char[] buffer, int index, int count) + { + _writer.WriteRaw(buffer, index, count); + } + + internal void WriteRaw(string data) + { + _writer.WriteRaw(data); + } + + + internal void WriteXmlnsAttribute(XmlDictionaryString ns) + { + if (_dictionaryWriter != null) + { + if (ns != null) + { + _dictionaryWriter.WriteXmlnsAttribute(null, ns); + } + } + else + { + WriteXmlnsAttribute(ns.Value); + } + } + + internal void WriteXmlnsAttribute(string ns) + { + if (ns != null) + { + if (ns.Length == 0) + { + _writer.WriteAttributeString("xmlns", string.Empty, null, ns); + } + else + { + if (_dictionaryWriter != null) + { + _dictionaryWriter.WriteXmlnsAttribute(null, ns); + } + else + { + string prefix = _writer.LookupPrefix(ns); + if (prefix == null) + { + prefix = string.Format(CultureInfo.InvariantCulture, "d{0}p{1}", _depth, _prefixes); + _prefixes++; + _writer.WriteAttributeString("xmlns", prefix, null, ns); + } + } + } + } + } + + internal void WriteXmlnsAttribute(string prefix, XmlDictionaryString ns) + { + if (_dictionaryWriter != null) + { + _dictionaryWriter.WriteXmlnsAttribute(prefix, ns); + } + else + { + _writer.WriteAttributeString("xmlns", prefix, null, ns.Value); + } + } + + private void WriteStartAttribute(string prefix, string localName, string ns) + { + _writer.WriteStartAttribute(prefix, localName, ns); + } + + private void WriteStartAttribute(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri) + { + if (_dictionaryWriter != null) + { + _dictionaryWriter.WriteStartAttribute(prefix, localName, namespaceUri); + } + else + { + _writer.WriteStartAttribute(prefix, + (localName == null ? null : localName.Value), + (namespaceUri == null ? null : namespaceUri.Value)); + } + } + + internal void WriteAttributeString(string prefix, string localName, string ns, string value) + { + WriteStartAttribute(prefix, localName, ns); + WriteAttributeStringValue(value); + WriteEndAttribute(); + } + + internal void WriteAttributeString(string prefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, string value) + { + WriteStartAttribute(prefix, attrName, attrNs); + WriteAttributeStringValue(value); + WriteEndAttribute(); + } + + private void WriteAttributeStringValue(string value) + { + _writer.WriteValue(value); + } + + internal void WriteAttributeString(string prefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, XmlDictionaryString value) + { + WriteStartAttribute(prefix, attrName, attrNs); + WriteAttributeStringValue(value); + WriteEndAttribute(); + } + + private void WriteAttributeStringValue(XmlDictionaryString value) + { + if (_dictionaryWriter == null) + { + _writer.WriteString(value.Value); + } + else + { + _dictionaryWriter.WriteString(value); + } + } + + internal void WriteAttributeInt(string prefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, int value) + { + WriteStartAttribute(prefix, attrName, attrNs); + WriteAttributeIntValue(value); + WriteEndAttribute(); + } + + private void WriteAttributeIntValue(int value) + { + _writer.WriteValue(value); + } + + internal void WriteAttributeBool(string prefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, bool value) + { + WriteStartAttribute(prefix, attrName, attrNs); + WriteAttributeBoolValue(value); + WriteEndAttribute(); + } + + private void WriteAttributeBoolValue(bool value) + { + _writer.WriteValue(value); + } + + internal void WriteAttributeQualifiedName(string attrPrefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, string name, string ns) + { + WriteXmlnsAttribute(ns); + WriteStartAttribute(attrPrefix, attrName, attrNs); + WriteAttributeQualifiedNameValue(name, ns); + WriteEndAttribute(); + } + + private void WriteAttributeQualifiedNameValue(string name, string ns) + { + _writer.WriteQualifiedName(name, ns); + } + + internal void WriteAttributeQualifiedName(string attrPrefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteXmlnsAttribute(ns); + WriteStartAttribute(attrPrefix, attrName, attrNs); + WriteAttributeQualifiedNameValue(name, ns); + WriteEndAttribute(); + } + + private void WriteAttributeQualifiedNameValue(XmlDictionaryString name, XmlDictionaryString ns) + { + if (_dictionaryWriter == null) + { + _writer.WriteQualifiedName(name.Value, ns.Value); + } + else + { + _dictionaryWriter.WriteQualifiedName(name, ns); + } + } + + internal void WriteStartElement(string localName, string ns) + { + WriteStartElement(null, localName, ns); + } + + internal virtual void WriteStartElement(string prefix, string localName, string ns) + { + _writer.WriteStartElement(prefix, localName, ns); + _depth++; + _prefixes = 1; + } + + public void WriteStartElement(XmlDictionaryString localName, XmlDictionaryString namespaceUri) + { + WriteStartElement(null, localName, namespaceUri); + } + + internal void WriteStartElement(string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri) + { + if (_dictionaryWriter != null) + { + _dictionaryWriter.WriteStartElement(prefix, localName, namespaceUri); + } + else + { + _writer.WriteStartElement(prefix, (localName == null ? null : localName.Value), (namespaceUri == null ? null : namespaceUri.Value)); + } + + _depth++; + _prefixes = 1; + } + + internal void WriteStartElementPrimitive(XmlDictionaryString localName, XmlDictionaryString namespaceUri) + { + if (_dictionaryWriter != null) + { + _dictionaryWriter.WriteStartElement(null, localName, namespaceUri); + } + else + { + _writer.WriteStartElement(null, (localName == null ? null : localName.Value), (namespaceUri == null ? null : namespaceUri.Value)); + } + } + + internal void WriteEndElementPrimitive() + { + _writer.WriteEndElement(); + } + + internal WriteState WriteState => _writer.WriteState; + + internal string XmlLang => _writer.XmlLang; + + internal XmlSpace XmlSpace => _writer.XmlSpace; + + public void WriteNamespaceDecl(XmlDictionaryString ns) + { + WriteXmlnsAttribute(ns); + } + + private Exception CreateInvalidPrimitiveTypeException(Type type) + { + return new System.Runtime.Serialization.InvalidDataContractException(SR.Format(SR.InvalidPrimitiveType, DataContract.GetClrTypeFullName(type))); + } + + internal void WriteAnyType(object value) + { + WriteAnyType(value, value.GetType()); + } + + internal void WriteAnyType(object value, Type valueType) + { + bool handled = true; + switch (Type.GetTypeCode(valueType)) + { + case TypeCode.Boolean: + WriteBoolean((bool)value); + break; + case TypeCode.Char: + WriteChar((char)value); + break; + case TypeCode.Byte: + WriteUnsignedByte((byte)value); + break; + case TypeCode.Int16: + WriteShort((short)value); + break; + case TypeCode.Int32: + WriteInt((int)value); + break; + case TypeCode.Int64: + WriteLong((long)value); + break; + case TypeCode.Single: + WriteFloat((float)value); + break; + case TypeCode.Double: + WriteDouble((double)value); + break; + case TypeCode.Decimal: + WriteDecimal((decimal)value); + break; + case TypeCode.DateTime: + WriteDateTime((DateTime)value); + break; + case TypeCode.String: + WriteString((string)value); + break; + case TypeCode.SByte: + WriteSignedByte((sbyte)value); + break; + case TypeCode.UInt16: + WriteUnsignedShort((ushort)value); + break; + case TypeCode.UInt32: + WriteUnsignedInt((uint)value); + break; + case TypeCode.UInt64: + WriteUnsignedLong((ulong)value); + break; + case TypeCode.Empty: + case TypeCode.DBNull: + case TypeCode.Object: + default: + if (valueType == Globals.TypeOfByteArray) + { + WriteBase64((byte[])value); + } + else if (valueType == Globals.TypeOfObject) + { + //Write Nothing + } + else if (valueType == Globals.TypeOfTimeSpan) + { + WriteTimeSpan((TimeSpan)value); + } + else if (valueType == Globals.TypeOfGuid) + { + WriteGuid((Guid)value); + } + else if (valueType == Globals.TypeOfUri) + { + WriteUri((Uri)value); + } + else if (valueType == Globals.TypeOfXmlQualifiedName) + { + WriteQName((XmlQualifiedName)value); + } + else + { + handled = false; + } + + break; + } + if (!handled) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidPrimitiveTypeException(valueType)); + } + } + + internal void WriteExtensionData(IDataNode dataNode) + { + bool handled = true; + Type valueType = dataNode.DataType; + switch (Type.GetTypeCode(valueType)) + { + case TypeCode.Boolean: + WriteBoolean(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Char: + WriteChar(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Byte: + WriteUnsignedByte(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Int16: + WriteShort(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Int32: + WriteInt(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Int64: + WriteLong(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Single: + WriteFloat(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Double: + WriteDouble(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Decimal: + WriteDecimal(((DataNode)dataNode).GetValue()); + break; + case TypeCode.DateTime: + WriteDateTime(((DataNode)dataNode).GetValue()); + break; + case TypeCode.String: + WriteString(((DataNode)dataNode).GetValue()); + break; + case TypeCode.SByte: + WriteSignedByte(((DataNode)dataNode).GetValue()); + break; + case TypeCode.UInt16: + WriteUnsignedShort(((DataNode)dataNode).GetValue()); + break; + case TypeCode.UInt32: + WriteUnsignedInt(((DataNode)dataNode).GetValue()); + break; + case TypeCode.UInt64: + WriteUnsignedLong(((DataNode)dataNode).GetValue()); + break; + case TypeCode.Empty: + case TypeCode.DBNull: + case TypeCode.Object: + default: + if (valueType == Globals.TypeOfByteArray) + { + WriteBase64(((DataNode)dataNode).GetValue()); + } + else if (valueType == Globals.TypeOfObject) + { + object obj = dataNode.Value; + if (obj != null) + { + WriteAnyType(obj); + } + } + else if (valueType == Globals.TypeOfTimeSpan) + { + WriteTimeSpan(((DataNode)dataNode).GetValue()); + } + else if (valueType == Globals.TypeOfGuid) + { + WriteGuid(((DataNode)dataNode).GetValue()); + } + else if (valueType == Globals.TypeOfUri) + { + WriteUri(((DataNode)dataNode).GetValue()); + } + else if (valueType == Globals.TypeOfXmlQualifiedName) + { + WriteQName(((DataNode)dataNode).GetValue()); + } + else + { + handled = false; + } + + break; + } + if (!handled) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidPrimitiveTypeException(valueType)); + } + } + + internal void WriteString(string value) + { + _writer.WriteValue(value); + } + + internal virtual void WriteBoolean(bool value) + { + _writer.WriteValue(value); + } + public void WriteBoolean(bool value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteBoolean(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteDateTime(DateTime value) + { + _writer.WriteValue(value); + } + + public void WriteDateTime(DateTime value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteDateTime(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteDecimal(decimal value) + { + _writer.WriteValue(value); + } + public void WriteDecimal(decimal value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteDecimal(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteDouble(double value) + { + _writer.WriteValue(value); + } + public void WriteDouble(double value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteDouble(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteInt(int value) + { + _writer.WriteValue(value); + } + public void WriteInt(int value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteInt(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteLong(long value) + { + _writer.WriteValue(value); + } + public void WriteLong(long value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteLong(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteFloat(float value) + { + _writer.WriteValue(value); + } + public void WriteFloat(float value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteFloat(value); + WriteEndElementPrimitive(); + } + + private const int CharChunkSize = 76; + private const int ByteChunkSize = CharChunkSize / 4 * 3; + + internal virtual void WriteBase64(byte[] bytes) + { + if (bytes == null) + { + return; + } + + _writer.WriteBase64(bytes, 0, bytes.Length); + } + + internal virtual void WriteShort(short value) + { + _writer.WriteValue(value); + } + public void WriteShort(short value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteShort(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteUnsignedByte(byte value) + { + _writer.WriteValue(value); + } + public void WriteUnsignedByte(byte value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteUnsignedByte(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteSignedByte(sbyte value) + { + _writer.WriteValue(value); + } + public void WriteSignedByte(sbyte value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteSignedByte(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteUnsignedInt(uint value) + { + _writer.WriteValue(value); + } + public void WriteUnsignedInt(uint value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteUnsignedInt(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteUnsignedLong(ulong value) + { + _writer.WriteRaw(XmlConvert.ToString(value)); + } + public void WriteUnsignedLong(ulong value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteUnsignedLong(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteUnsignedShort(ushort value) + { + _writer.WriteValue(value); + } + public void WriteUnsignedShort(ushort value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteUnsignedShort(value); + WriteEndElementPrimitive(); + } + + internal virtual void WriteChar(char value) + { + _writer.WriteValue(value); + } + public void WriteChar(char value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteChar(value); + WriteEndElementPrimitive(); + } + + internal void WriteTimeSpan(TimeSpan value) + { + _writer.WriteRaw(XmlConvert.ToString(value)); + } + public void WriteTimeSpan(TimeSpan value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteTimeSpan(value); + WriteEndElementPrimitive(); + } + + internal void WriteGuid(Guid value) + { + _writer.WriteRaw(value.ToString()); + } + public void WriteGuid(Guid value, XmlDictionaryString name, XmlDictionaryString ns) + { + WriteStartElementPrimitive(name, ns); + WriteGuid(value); + WriteEndElementPrimitive(); + } + + internal void WriteUri(Uri value) + { + _writer.WriteString(value.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); + } + + internal virtual void WriteQName(XmlQualifiedName value) + { + if (value != XmlQualifiedName.Empty) + { + WriteXmlnsAttribute(value.Namespace); + WriteQualifiedName(value.Name, value.Namespace); + } + } + + internal void WriteQualifiedName(string localName, string ns) + { + _writer.WriteQualifiedName(localName, ns); + } + + internal void WriteQualifiedName(XmlDictionaryString localName, XmlDictionaryString ns) + { + if (_dictionaryWriter == null) + { + _writer.WriteQualifiedName(localName.Value, ns.Value); + } + else + { + _dictionaryWriter.WriteQualifiedName(localName, ns); + } + } + + public void WriteBooleanArray(bool[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteBoolean(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + public void WriteDateTimeArray(DateTime[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteDateTime(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + public void WriteDecimalArray(decimal[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteDecimal(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + public void WriteInt32Array(int[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteInt(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + public void WriteInt64Array(long[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteLong(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + public void WriteSingleArray(float[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteFloat(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + public void WriteDoubleArray(double[] value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) + { + if (_dictionaryWriter == null) + { + for (int i = 0; i < value.Length; i++) + { + WriteDouble(value[i], itemName, itemNamespace); + } + } + else + { + _dictionaryWriter.WriteArray(null, itemName, itemNamespace, value, 0, value.Length); + } + } + + } +} diff --git a/Compat.Private.Serialization/Compat/Runtime/Serialization/XsdDataContractExporter.cs b/Compat.Private.Serialization/Compat/Runtime/Serialization/XsdDataContractExporter.cs new file mode 100644 index 0000000..0cd0408 --- /dev/null +++ b/Compat.Private.Serialization/Compat/Runtime/Serialization/XsdDataContractExporter.cs @@ -0,0 +1,387 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using InvalidDataContractException = System.Runtime.Serialization.InvalidDataContractException; + +namespace Compat.Runtime.Serialization +{ + + public class XsdDataContractExporter + { + private ExportOptions options; + private XmlSchemaSet schemas; + private DataContractSet dataContractSet; + + public XsdDataContractExporter() + { + } + + public XsdDataContractExporter(XmlSchemaSet schemas) + { + this.schemas = schemas; + } + + public ExportOptions Options + { + get => options; + set => options = value; + } + + public XmlSchemaSet Schemas + { + get + { + XmlSchemaSet schemaSet = GetSchemaSet(); + SchemaImporter.CompileSchemaSet(schemaSet); + return schemaSet; + } + } + + private XmlSchemaSet GetSchemaSet() + { + if (schemas == null) + { + schemas = new XmlSchemaSet + { + XmlResolver = null + }; + } + return schemas; + } + + private DataContractSet DataContractSet + { + get + { + if (dataContractSet == null) + { + dataContractSet = new DataContractSet((Options == null) ? null : Options.GetSurrogate()); + } + return dataContractSet; + } + } + + public void Export(ICollection assemblies) + { + if (assemblies == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("assemblies")); + } + + DataContractSet oldValue = (dataContractSet == null) ? null : new DataContractSet(dataContractSet); + try + { + foreach (Assembly assembly in assemblies) + { + if (assembly == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullAssembly, "assemblies"))); + } + + Type[] types = assembly.GetTypes(); + for (int j = 0; j < types.Length; j++) + { + CheckAndAddType(types[j]); + } + } + + Export(); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + dataContractSet = oldValue; + throw; + } + } + + public void Export(ICollection types) + { + if (types == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(types))); + } + + DataContractSet oldValue = (dataContractSet == null) ? null : new DataContractSet(dataContractSet); + try + { + foreach (Type type in types) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullType, nameof(types)))); + } + + AddType(type); + } + + Export(); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + dataContractSet = oldValue; + throw; + } + } + + public void Export(Type type) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(type))); + } + + DataContractSet oldValue = (dataContractSet == null) ? null : new DataContractSet(dataContractSet); + try + { + AddType(type); + Export(); + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + dataContractSet = oldValue; + throw; + } + } + + public XmlQualifiedName GetSchemaTypeName(Type type) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(type))); + } + + type = GetSurrogatedType(type); + DataContract dataContract = DataContract.GetDataContract(type); + DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); + XmlDataContract xmlDataContract = dataContract as XmlDataContract; + if (xmlDataContract != null && xmlDataContract.IsAnonymous) + { + return XmlQualifiedName.Empty; + } + + return dataContract.StableName; + } + + public XmlSchemaType GetSchemaType(Type type) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("type")); + } + + type = GetSurrogatedType(type); + DataContract dataContract = DataContract.GetDataContract(type); + DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); + XmlDataContract xmlDataContract = dataContract as XmlDataContract; + if (xmlDataContract != null && xmlDataContract.IsAnonymous) + { + return xmlDataContract.XsdType; + } + + return null; + } + + public XmlQualifiedName GetRootElementName(Type type) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("type")); + } + + type = GetSurrogatedType(type); + DataContract dataContract = DataContract.GetDataContract(type); + DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); + if (dataContract.HasRoot) + { + return new XmlQualifiedName(dataContract.TopLevelElementName.Value, dataContract.TopLevelElementNamespace.Value); + } + else + { + return null; + } + } + + private Type GetSurrogatedType(Type type) + { + IDataContractSurrogate dataContractSurrogate; + if (options != null && (dataContractSurrogate = Options.GetSurrogate()) != null) + { + type = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, type); + } + + return type; + } + + private void CheckAndAddType(Type type) + { + type = GetSurrogatedType(type); + if (!type.ContainsGenericParameters && DataContract.IsTypeSerializable(type)) + { + AddType(type); + } + } + + private void AddType(Type type) + { + DataContractSet.Add(type); + } + + private void Export() + { + AddKnownTypes(); + SchemaExporter schemaExporter = new SchemaExporter(GetSchemaSet(), DataContractSet); + schemaExporter.Export(); + } + + private void AddKnownTypes() + { + if (Options != null) + { + Collection knownTypes = Options.KnownTypes; + + if (knownTypes != null) + { + for (int i = 0; i < knownTypes.Count; i++) + { + Type type = knownTypes[i]; + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.CannotExportNullKnownType)); + } + + AddType(type); + } + } + } + } + + public bool CanExport(ICollection assemblies) + { + if (assemblies == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("assemblies")); + } + + DataContractSet oldValue = (dataContractSet == null) ? null : new DataContractSet(dataContractSet); + try + { + foreach (Assembly assembly in assemblies) + { + if (assembly == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullAssembly, nameof(assemblies)))); + } + + Type[] types = assembly.GetTypes(); + for (int j = 0; j < types.Length; j++) + { + CheckAndAddType(types[j]); + } + } + AddKnownTypes(); + return true; + } + catch (InvalidDataContractException) + { + dataContractSet = oldValue; + return false; + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + dataContractSet = oldValue; + throw; + } + } + + public bool CanExport(ICollection types) + { + if (types == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(types))); + } + + DataContractSet oldValue = (dataContractSet == null) ? null : new DataContractSet(dataContractSet); + try + { + foreach (Type type in types) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullType, nameof(types)))); + } + + AddType(type); + } + AddKnownTypes(); + return true; + } + catch (InvalidDataContractException) + { + dataContractSet = oldValue; + return false; + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + dataContractSet = oldValue; + throw; + } + } + + public bool CanExport(Type type) + { + if (type == null) + { + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(type))); + } + + DataContractSet oldValue = (dataContractSet == null) ? null : new DataContractSet(dataContractSet); + try + { + AddType(type); + AddKnownTypes(); + return true; + } + catch (InvalidDataContractException) + { + dataContractSet = oldValue; + return false; + } + catch (Exception ex) + { + if (Fx.IsFatal(ex)) + { + throw; + } + dataContractSet = oldValue; + throw; + } + } + } +} + diff --git a/Compat.Private.Serialization/Compat/Text/Base64Encoding.cs b/Compat.Private.Serialization/Compat/Text/Base64Encoding.cs new file mode 100644 index 0000000..73cdc3f --- /dev/null +++ b/Compat.Private.Serialization/Compat/Text/Base64Encoding.cs @@ -0,0 +1,601 @@ +using Compat.Runtime.Serialization; +using System; +using System.Globalization; +using System.Security; +using System.Text; + +namespace Compat.Text +{ + internal class Base64Encoding : Encoding + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.SpacingRules", "SA1025:CodeMustNotContainMultipleWhitespaceInARow", Justification = "This alignment is optimal.")] + private static readonly byte[] char2val = new byte[128] + { + /* 0-15 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* 16-31 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* 32-47 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63, + /* 48-63 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, 0xFF, 64, 0xFF, 0xFF, + /* 64-79 */ 0xFF, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + /* 80-95 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* 96-111 */ 0xFF, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + /* 112-127 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }; + private static readonly string val2char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + private static readonly byte[] val2byte = new byte[] + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P', + (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', + (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' + }; + + public override int GetMaxByteCount(int charCount) + { + if (charCount < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charCount), SR.ValueMustBeNonNegative)); + } + + if ((charCount % 4) != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Length, charCount.ToString(NumberFormatInfo.CurrentInfo)))); + } + + return charCount / 4 * 3; + } + + private bool IsValidLeadBytes(int v1, int v2, int v3, int v4) + { + // First two chars of a four char base64 sequence can't be ==, and must be valid + return ((v1 | v2) < 64) && ((v3 | v4) != 0xFF); + } + + private bool IsValidTailBytes(int v3, int v4) + { + // If the third char is = then the fourth char must be = + return !(v3 == 64 && v4 != 64); + } + + public override unsafe int GetByteCount(char[] chars, int index, int count) + { + if (chars == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(chars))); + } + + if (index < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(index), SR.ValueMustBeNonNegative)); + } + + if (index > chars.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(index), SR.Format(SR.OffsetExceedsBufferSize, chars.Length))); + } + + if (count < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.ValueMustBeNonNegative)); + } + + if (count > chars.Length - index) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, chars.Length - index))); + } + + if (count == 0) + { + return 0; + } + + if ((count % 4) != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Length, count.ToString(NumberFormatInfo.CurrentInfo)))); + } + + fixed (byte* _char2val = char2val) + { + fixed (char* _chars = &chars[index]) + { + int totalCount = 0; + char* pch = _chars; + char* pchMax = _chars + count; + while (pch < pchMax) + { + Fx.Assert(pch + 4 <= pchMax, ""); + char pch0 = pch[0]; + char pch1 = pch[1]; + char pch2 = pch[2]; + char pch3 = pch[3]; + + if ((pch0 | pch1 | pch2 | pch3) >= 128) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), index + (int)(pch - _chars)))); + } + + // xx765432 xx107654 xx321076 xx543210 + // 76543210 76543210 76543210 + int v1 = _char2val[pch0]; + int v2 = _char2val[pch1]; + int v3 = _char2val[pch2]; + int v4 = _char2val[pch3]; + + if (!IsValidLeadBytes(v1, v2, v3, v4) || !IsValidTailBytes(v3, v4)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), index + (int)(pch - _chars)))); + } + + int byteCount = (v4 != 64 ? 3 : (v3 != 64 ? 2 : 1)); + totalCount += byteCount; + pch += 4; + } + return totalCount; + } + } + } + + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) + { + if (chars == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(chars))); + } + + if (charIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.ValueMustBeNonNegative)); + } + + if (charIndex > chars.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.Format(SR.OffsetExceedsBufferSize, chars.Length))); + } + + if (charCount < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charCount), SR.ValueMustBeNonNegative)); + } + + if (charCount > chars.Length - charIndex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charCount), SR.Format(SR.SizeExceedsRemainingBufferSpace, chars.Length - charIndex))); + } + + if (bytes == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(bytes))); + } + + if (byteIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.ValueMustBeNonNegative)); + } + + if (byteIndex > bytes.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.Format(SR.OffsetExceedsBufferSize, bytes.Length))); + } + + if (charCount == 0) + { + return 0; + } + + if ((charCount % 4) != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Length, charCount.ToString(NumberFormatInfo.CurrentInfo)))); + } + + fixed (byte* _char2val = char2val) + { + fixed (char* _chars = &chars[charIndex]) + { + fixed (byte* _bytes = &bytes[byteIndex]) + { + char* pch = _chars; + char* pchMax = _chars + charCount; + byte* pb = _bytes; + byte* pbMax = _bytes + bytes.Length - byteIndex; + while (pch < pchMax) + { + Fx.Assert(pch + 4 <= pchMax, ""); + char pch0 = pch[0]; + char pch1 = pch[1]; + char pch2 = pch[2]; + char pch3 = pch[3]; + + if ((pch0 | pch1 | pch2 | pch3) >= 128) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), charIndex + (int)(pch - _chars)))); + } + // xx765432 xx107654 xx321076 xx543210 + // 76543210 76543210 76543210 + + int v1 = _char2val[pch0]; + int v2 = _char2val[pch1]; + int v3 = _char2val[pch2]; + int v4 = _char2val[pch3]; + + if (!IsValidLeadBytes(v1, v2, v3, v4) || !IsValidTailBytes(v3, v4)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), charIndex + (int)(pch - _chars)))); + } + + int byteCount = (v4 != 64 ? 3 : (v3 != 64 ? 2 : 1)); + if (pb + byteCount > pbMax) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.XmlArrayTooSmall, nameof(bytes))); + } + + pb[0] = (byte)((v1 << 2) | ((v2 >> 4) & 0x03)); + if (byteCount > 1) + { + pb[1] = (byte)((v2 << 4) | ((v3 >> 2) & 0x0F)); + if (byteCount > 2) + { + pb[2] = (byte)((v3 << 6) | ((v4 >> 0) & 0x3F)); + } + } + pb += byteCount; + pch += 4; + } + return (int)(pb - _bytes); + } + } + } + } + + public virtual unsafe int GetBytes(byte[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) + { + if (chars == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(chars))); + } + + if (charIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.ValueMustBeNonNegative)); + } + + if (charIndex > chars.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.Format(SR.OffsetExceedsBufferSize, chars.Length))); + } + + if (charCount < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charCount), SR.ValueMustBeNonNegative)); + } + + if (charCount > chars.Length - charIndex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charCount), SR.Format(SR.SizeExceedsRemainingBufferSpace, chars.Length - charIndex))); + } + + if (bytes == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(bytes))); + } + + if (byteIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.ValueMustBeNonNegative)); + } + + if (byteIndex > bytes.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.Format(SR.OffsetExceedsBufferSize, bytes.Length))); + } + + if (charCount == 0) + { + return 0; + } + + if ((charCount % 4) != 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Length, charCount.ToString(NumberFormatInfo.CurrentInfo)))); + } + + fixed (byte* _char2val = char2val) + { + fixed (byte* _chars = &chars[charIndex]) + { + fixed (byte* _bytes = &bytes[byteIndex]) + { + byte* pch = _chars; + byte* pchMax = _chars + charCount; + byte* pb = _bytes; + byte* pbMax = _bytes + bytes.Length - byteIndex; + while (pch < pchMax) + { + Fx.Assert(pch + 4 <= pchMax, ""); + byte pch0 = pch[0]; + byte pch1 = pch[1]; + byte pch2 = pch[2]; + byte pch3 = pch[3]; + if ((pch0 | pch1 | pch2 | pch3) >= 128) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Sequence, new string((sbyte*)pch, 0, 4), charIndex + (int)(pch - _chars)))); + } + // xx765432 xx107654 xx321076 xx543210 + // 76543210 76543210 76543210 + + int v1 = _char2val[pch0]; + int v2 = _char2val[pch1]; + int v3 = _char2val[pch2]; + int v4 = _char2val[pch3]; + + if (!IsValidLeadBytes(v1, v2, v3, v4) || !IsValidTailBytes(v3, v4)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.Format(SR.XmlInvalidBase64Sequence, new string((sbyte*)pch, 0, 4), charIndex + (int)(pch - _chars)))); + } + + int byteCount = (v4 != 64 ? 3 : (v3 != 64 ? 2 : 1)); + if (pb + byteCount > pbMax) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.XmlArrayTooSmall, nameof(bytes))); + } + + pb[0] = (byte)((v1 << 2) | ((v2 >> 4) & 0x03)); + if (byteCount > 1) + { + pb[1] = (byte)((v2 << 4) | ((v3 >> 2) & 0x0F)); + if (byteCount > 2) + { + pb[2] = (byte)((v3 << 6) | ((v4 >> 0) & 0x3F)); + } + } + pb += byteCount; + pch += 4; + } + return (int)(pb - _bytes); + } + } + } + } + + public override int GetMaxCharCount(int byteCount) + { + if (byteCount < 0 || byteCount > int.MaxValue / 4 * 3 - 2) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteCount), SR.Format(SR.ValueMustBeInRange, 0, int.MaxValue / 4 * 3 - 2))); + } + + return ((byteCount + 2) / 3) * 4; + } + + public override int GetCharCount(byte[] bytes, int index, int count) + { + return GetMaxCharCount(count); + } + + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) + { + if (bytes == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(bytes))); + } + + if (byteIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.ValueMustBeNonNegative)); + } + + if (byteIndex > bytes.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.Format(SR.OffsetExceedsBufferSize, bytes.Length))); + } + + if (byteCount < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteCount), SR.ValueMustBeNonNegative)); + } + + if (byteCount > bytes.Length - byteIndex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteCount), SR.Format(SR.SizeExceedsRemainingBufferSpace, bytes.Length - byteIndex))); + } + + int charCount = GetCharCount(bytes, byteIndex, byteCount); + if (chars == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(chars))); + } + + if (charIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.ValueMustBeNonNegative)); + } + + if (charIndex > chars.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.Format(SR.OffsetExceedsBufferSize, chars.Length))); + } + + if (charCount < 0 || charCount > chars.Length - charIndex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.XmlArrayTooSmall, nameof(chars))); + } + + // We've computed exactly how many chars there are and verified that + // there's enough space in the char buffer, so we can proceed without + // checking the charCount. + + if (byteCount > 0) + { + fixed (char* _val2char = val2char) + { + fixed (byte* _bytes = &bytes[byteIndex]) + { + fixed (char* _chars = &chars[charIndex]) + { + byte* pb = _bytes; + byte* pbMax = pb + byteCount - 3; + char* pch = _chars; + + // Convert chunks of 3 bytes to 4 chars + while (pb <= pbMax) + { + // 76543210 76543210 76543210 + // xx765432 xx107654 xx321076 xx543210 + + // Inspect the code carefully before you change this + pch[0] = _val2char[(pb[0] >> 2)]; + pch[1] = _val2char[((pb[0] & 0x03) << 4) | (pb[1] >> 4)]; + pch[2] = _val2char[((pb[1] & 0x0F) << 2) | (pb[2] >> 6)]; + pch[3] = _val2char[pb[2] & 0x3F]; + + pb += 3; + pch += 4; + } + + // Handle 1 or 2 trailing bytes + if (pb - pbMax == 2) + { + // 1 trailing byte + // 76543210 xxxxxxxx xxxxxxxx + // xx765432 xx10xxxx xxxxxxxx xxxxxxxx + pch[0] = _val2char[(pb[0] >> 2)]; + pch[1] = _val2char[((pb[0] & 0x03) << 4)]; + pch[2] = '='; + pch[3] = '='; + } + else if (pb - pbMax == 1) + { + // 2 trailing bytes + // 76543210 76543210 xxxxxxxx + // xx765432 xx107654 xx3210xx xxxxxxxx + pch[0] = _val2char[(pb[0] >> 2)]; + pch[1] = _val2char[((pb[0] & 0x03) << 4) | (pb[1] >> 4)]; + pch[2] = _val2char[((pb[1] & 0x0F) << 2)]; + pch[3] = '='; + } + else + { + // 0 trailing bytes + Fx.Assert(pb - pbMax == 3, ""); + } + } + } + } + } + + return charCount; + } + + public unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, byte[] chars, int charIndex) + { + if (bytes == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(bytes))); + } + + if (byteIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.ValueMustBeNonNegative)); + } + + if (byteIndex > bytes.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteIndex), SR.Format(SR.OffsetExceedsBufferSize, bytes.Length))); + } + + if (byteCount < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteCount), SR.ValueMustBeNonNegative)); + } + + if (byteCount > bytes.Length - byteIndex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(byteCount), SR.Format(SR.SizeExceedsRemainingBufferSpace, bytes.Length - byteIndex))); + } + + int charCount = GetCharCount(bytes, byteIndex, byteCount); + if (chars == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(chars))); + } + + if (charIndex < 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.ValueMustBeNonNegative)); + } + + if (charIndex > chars.Length) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(charIndex), SR.Format(SR.OffsetExceedsBufferSize, chars.Length))); + } + + if (charCount < 0 || charCount > chars.Length - charIndex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.XmlArrayTooSmall, nameof(chars))); + } + + // We've computed exactly how many chars there are and verified that + // there's enough space in the char buffer, so we can proceed without + // checking the charCount. + + if (byteCount > 0) + { + fixed (byte* _val2byte = val2byte) + { + fixed (byte* _bytes = &bytes[byteIndex]) + { + fixed (byte* _chars = &chars[charIndex]) + { + byte* pb = _bytes; + byte* pbMax = pb + byteCount - 3; + byte* pch = _chars; + + // Convert chunks of 3 bytes to 4 chars + while (pb <= pbMax) + { + // 76543210 76543210 76543210 + // xx765432 xx107654 xx321076 xx543210 + + // Inspect the code carefully before you change this + pch[0] = _val2byte[(pb[0] >> 2)]; + pch[1] = _val2byte[((pb[0] & 0x03) << 4) | (pb[1] >> 4)]; + pch[2] = _val2byte[((pb[1] & 0x0F) << 2) | (pb[2] >> 6)]; + pch[3] = _val2byte[pb[2] & 0x3F]; + + pb += 3; + pch += 4; + } + + // Handle 1 or 2 trailing bytes + if (pb - pbMax == 2) + { + // 1 trailing byte + // 76543210 xxxxxxxx xxxxxxxx + // xx765432 xx10xxxx xxxxxxxx xxxxxxxx + pch[0] = _val2byte[(pb[0] >> 2)]; + pch[1] = _val2byte[((pb[0] & 0x03) << 4)]; + pch[2] = (byte)'='; + pch[3] = (byte)'='; + } + else if (pb - pbMax == 1) + { + // 2 trailing bytes + // 76543210 76543210 xxxxxxxx + // xx765432 xx107654 xx3210xx xxxxxxxx + pch[0] = _val2byte[(pb[0] >> 2)]; + pch[1] = _val2byte[((pb[0] & 0x03) << 4) | (pb[1] >> 4)]; + pch[2] = _val2byte[((pb[1] & 0x0F) << 2)]; + pch[3] = (byte)'='; + } + else + { + // 0 trailing bytes + Fx.Assert(pb - pbMax == 3, ""); + } + } + } + } + } + + return charCount; + } + } +} diff --git a/Compat.Private.Serialization/Compat/Xml/ArrayHelper.cs b/Compat.Private.Serialization/Compat/Xml/ArrayHelper.cs new file mode 100644 index 0000000..80f652b --- /dev/null +++ b/Compat.Private.Serialization/Compat/Xml/ArrayHelper.cs @@ -0,0 +1,422 @@ +using System; +using System.Xml; + +namespace Compat.Xml +{ + internal abstract class ArrayHelper + { + private const int MaxInitialArrayLength = 65535; + + public TArray[] ReadArray(XmlDictionaryReader reader, TArgument localName, TArgument namespaceUri, int maxArrayLength) + { + TArray[][] arrays = null; + TArray[] array = null; + int arrayCount = 0; + int totalRead = 0; + if (reader.TryGetArrayLength(out int count)) + { + if (count > maxArrayLength) + { + XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength); + } + + if (count > MaxInitialArrayLength) + { + count = MaxInitialArrayLength; + } + } + else + { + count = 32; + } + while (true) + { + array = new TArray[count]; + int read = 0; + while (read < array.Length) + { + int actual = ReadArray(reader, localName, namespaceUri, array, read, array.Length - read); + if (actual == 0) + { + break; + } + + read += actual; + } + if (totalRead > maxArrayLength - read) + { + XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength); + } + + totalRead += read; + if (read < array.Length || reader.NodeType == XmlNodeType.EndElement) + { + break; + } + + if (arrays == null) + { + arrays = new TArray[32][]; + } + + arrays[arrayCount++] = array; + count = count * 2; + } + if (totalRead != array.Length || arrayCount > 0) + { + TArray[] newArray = new TArray[totalRead]; + int offset = 0; + for (int i = 0; i < arrayCount; i++) + { + Array.Copy(arrays[i], 0, newArray, offset, arrays[i].Length); + offset += arrays[i].Length; + } + Array.Copy(array, 0, newArray, offset, totalRead - offset); + array = newArray; + } + return array; + } + + public void WriteArray(XmlDictionaryWriter writer, string prefix, TArgument localName, TArgument namespaceUri, XmlDictionaryReader reader) + { + if (reader.TryGetArrayLength(out int count)) + { + count = Math.Min(count, 256); + } + else + { + count = 256; + } + + TArray[] array = new TArray[count]; + while (true) + { + int actual = ReadArray(reader, localName, namespaceUri, array, 0, array.Length); + if (actual == 0) + { + break; + } + + WriteArray(writer, prefix, localName, namespaceUri, array, 0, actual); + } + } + + protected abstract int ReadArray(XmlDictionaryReader reader, TArgument localName, TArgument namespaceUri, TArray[] array, int offset, int count); + protected abstract void WriteArray(XmlDictionaryWriter writer, string prefix, TArgument localName, TArgument namespaceUri, TArray[] array, int offset, int count); + } + + // Supported array types + // bool + // Int16 + // Int32 + // Int64 + // Float + // Double + // Decimal + // DateTime + // Guid + // TimeSpan + + // Int8 is not supported since sbyte[] is non-cls compliant, and uncommon + // UniqueId is not supported since elements may be variable size strings + + internal class BooleanArrayHelperWithString : ArrayHelper + { + public static readonly BooleanArrayHelperWithString Instance = new BooleanArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, bool[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, bool[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class BooleanArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly BooleanArrayHelperWithDictionaryString Instance = new BooleanArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, bool[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class Int16ArrayHelperWithString : ArrayHelper + { + public static readonly Int16ArrayHelperWithString Instance = new Int16ArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, short[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, short[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class Int16ArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly Int16ArrayHelperWithDictionaryString Instance = new Int16ArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, short[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class Int32ArrayHelperWithString : ArrayHelper + { + public static readonly Int32ArrayHelperWithString Instance = new Int32ArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, int[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, int[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class Int32ArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly Int32ArrayHelperWithDictionaryString Instance = new Int32ArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, int[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class Int64ArrayHelperWithString : ArrayHelper + { + public static readonly Int64ArrayHelperWithString Instance = new Int64ArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, long[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, long[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class Int64ArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly Int64ArrayHelperWithDictionaryString Instance = new Int64ArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, long[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class SingleArrayHelperWithString : ArrayHelper + { + public static readonly SingleArrayHelperWithString Instance = new SingleArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, float[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, float[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class SingleArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly SingleArrayHelperWithDictionaryString Instance = new SingleArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, float[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class DoubleArrayHelperWithString : ArrayHelper + { + public static readonly DoubleArrayHelperWithString Instance = new DoubleArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, double[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, double[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class DoubleArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly DoubleArrayHelperWithDictionaryString Instance = new DoubleArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, double[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class DecimalArrayHelperWithString : ArrayHelper + { + public static readonly DecimalArrayHelperWithString Instance = new DecimalArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, decimal[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, decimal[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class DecimalArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly DecimalArrayHelperWithDictionaryString Instance = new DecimalArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, decimal[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class DateTimeArrayHelperWithString : ArrayHelper + { + public static readonly DateTimeArrayHelperWithString Instance = new DateTimeArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, DateTime[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, DateTime[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class DateTimeArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly DateTimeArrayHelperWithDictionaryString Instance = new DateTimeArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, DateTime[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class GuidArrayHelperWithString : ArrayHelper + { + public static readonly GuidArrayHelperWithString Instance = new GuidArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, Guid[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, Guid[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class GuidArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly GuidArrayHelperWithDictionaryString Instance = new GuidArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, Guid[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class TimeSpanArrayHelperWithString : ArrayHelper + { + public static readonly TimeSpanArrayHelperWithString Instance = new TimeSpanArrayHelperWithString(); + + protected override int ReadArray(XmlDictionaryReader reader, string localName, string namespaceUri, TimeSpan[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, string localName, string namespaceUri, TimeSpan[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } + + internal class TimeSpanArrayHelperWithDictionaryString : ArrayHelper + { + public static readonly TimeSpanArrayHelperWithDictionaryString Instance = new TimeSpanArrayHelperWithDictionaryString(); + + protected override int ReadArray(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count) + { + return reader.ReadArray(localName, namespaceUri, array, offset, count); + } + + protected override void WriteArray(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString namespaceUri, TimeSpan[] array, int offset, int count) + { + writer.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + } +} diff --git a/Compat.Private.Serialization/Compat/Xml/XmlExceptionHelper.cs b/Compat.Private.Serialization/Compat/Xml/XmlExceptionHelper.cs new file mode 100644 index 0000000..2c3e76b --- /dev/null +++ b/Compat.Private.Serialization/Compat/Xml/XmlExceptionHelper.cs @@ -0,0 +1,288 @@ +////using System.ServiceModel.Channels; +using System; +using System.Globalization; +using System.Xml; + +namespace Compat.Xml +{ + internal static class XmlExceptionHelper + { + private static void ThrowXmlException(XmlDictionaryReader reader, string res) + { + ThrowXmlException(reader, res, null); + } + + private static void ThrowXmlException(XmlDictionaryReader reader, string res, string arg1) + { + ThrowXmlException(reader, res, arg1, null); + } + + private static void ThrowXmlException(XmlDictionaryReader reader, string res, string arg1, string arg2) + { + ThrowXmlException(reader, res, arg1, arg2, null); + } + + private static void ThrowXmlException(XmlDictionaryReader reader, string res, string arg1, string arg2, string arg3) + { + string s = SR.Format(res, arg1, arg2, arg3); + if (reader is IXmlLineInfo lineInfo && lineInfo.HasLineInfo()) + { + s += " " + SR.Format(SR.XmlLineInfo, lineInfo.LineNumber, lineInfo.LinePosition); + } + + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new System.Xml.XmlException(s)); + } + + public static void ThrowXmlException(XmlDictionaryReader reader, XmlException exception) + { + string s = exception.Message; + if (reader is IXmlLineInfo lineInfo && lineInfo.HasLineInfo()) + { + s += " " + SR.Format(SR.XmlLineInfo, lineInfo.LineNumber, lineInfo.LinePosition); + } + throw Compat.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(s)); + } + + private static string GetName(string prefix, string localName) + { + if (prefix.Length == 0) + { + return localName; + } + else + { + return string.Concat(prefix, ":", localName); + } + } + + private static string GetWhatWasFound(XmlDictionaryReader reader) + { + if (reader.EOF) + { + return SR.XmlFoundEndOfFile; + } + + switch (reader.NodeType) + { + case XmlNodeType.Element: + return SR.Format(SR.XmlFoundElement, GetName(reader.Prefix, reader.LocalName), reader.NamespaceURI); + case XmlNodeType.EndElement: + return SR.Format(SR.XmlFoundEndElement, GetName(reader.Prefix, reader.LocalName), reader.NamespaceURI); + case XmlNodeType.Text: + case XmlNodeType.Whitespace: + case XmlNodeType.SignificantWhitespace: + return SR.Format(SR.XmlFoundText, reader.Value); + case XmlNodeType.Comment: + return SR.Format(SR.XmlFoundComment, reader.Value); + case XmlNodeType.CDATA: + return SR.Format(SR.XmlFoundCData, reader.Value); + } + return SR.Format(SR.XmlFoundNodeType, reader.NodeType); + } + + //public static void ThrowStartElementExpected(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlStartElementExpected, GetWhatWasFound(reader)); + //} + + //public static void ThrowStartElementExpected(XmlDictionaryReader reader, string name) + //{ + // ThrowXmlException(reader, SR.XmlStartElementNameExpected, name, GetWhatWasFound(reader)); + //} + + //public static void ThrowStartElementExpected(XmlDictionaryReader reader, string localName, string ns) + //{ + // ThrowXmlException(reader, SR.XmlStartElementLocalNameNsExpected, localName, ns, GetWhatWasFound(reader)); + //} + + //public static void ThrowStartElementExpected(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns) + //{ + // ThrowStartElementExpected(reader, localName?.Value, ns?.Value); + //} + + //public static void ThrowFullStartElementExpected(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlFullStartElementExpected, GetWhatWasFound(reader)); + //} + + //public static void ThrowFullStartElementExpected(XmlDictionaryReader reader, string name) + //{ + // ThrowXmlException(reader, SR.XmlFullStartElementNameExpected, name, GetWhatWasFound(reader)); + //} + + //public static void ThrowFullStartElementExpected(XmlDictionaryReader reader, string localName, string ns) + //{ + // ThrowXmlException(reader, SR.XmlFullStartElementLocalNameNsExpected, localName, ns, GetWhatWasFound(reader)); + //} + + //public static void ThrowFullStartElementExpected(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns) + //{ + // ThrowFullStartElementExpected(reader, localName?.Value, ns?.Value); + //} + + //public static void ThrowEndElementExpected(XmlDictionaryReader reader, string localName, string ns) + //{ + // ThrowXmlException(reader, SR.XmlEndElementExpected, localName, ns, GetWhatWasFound(reader)); + //} + + //public static void ThrowMaxStringContentLengthExceeded(XmlDictionaryReader reader, int maxStringContentLength) + //{ + // ThrowXmlException(reader, SR.XmlMaxStringContentLengthExceeded, maxStringContentLength.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowMaxArrayLengthExceeded(XmlDictionaryReader reader, int maxArrayLength) + //{ + // ThrowXmlException(reader, SR.XmlMaxArrayLengthExceeded, maxArrayLength.ToString(NumberFormatInfo.CurrentInfo)); + //} + + public static void ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(XmlDictionaryReader reader, int maxQuota) + { + ThrowXmlException(reader, SR.XmlMaxArrayLengthOrMaxItemsQuotaExceeded, maxQuota.ToString(NumberFormatInfo.CurrentInfo)); + } + + //public static void ThrowMaxDepthExceeded(XmlDictionaryReader reader, int maxDepth) + //{ + // ThrowXmlException(reader, SR.XmlMaxDepthExceeded, maxDepth.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowMaxBytesPerReadExceeded(XmlDictionaryReader reader, int maxBytesPerRead) + //{ + // ThrowXmlException(reader, SR.XmlMaxBytesPerReadExceeded, maxBytesPerRead.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowMaxNameTableCharCountExceeded(XmlDictionaryReader reader, int maxNameTableCharCount) + //{ + // ThrowXmlException(reader, SR.XmlMaxNameTableCharCountExceeded, maxNameTableCharCount.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowBase64DataExpected(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlBase64DataExpected, GetWhatWasFound(reader)); + //} + + //public static void ThrowUndefinedPrefix(XmlDictionaryReader reader, string prefix) + //{ + // ThrowXmlException(reader, SR.XmlUndefinedPrefix, prefix); + //} + + //public static void ThrowProcessingInstructionNotSupported(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlProcessingInstructionNotSupported); + //} + + //public static void ThrowInvalidXml(XmlDictionaryReader reader, byte b) + //{ + // ThrowXmlException(reader, SR.XmlInvalidXmlByte, b.ToString("X2", CultureInfo.InvariantCulture)); + //} + + //public static void ThrowUnexpectedEndOfFile(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlUnexpectedEndOfFile, ((XmlBaseReader)reader).GetOpenElements()); + //} + + //public static void ThrowUnexpectedEndElement(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlUnexpectedEndElement); + //} + + //public static void ThrowTokenExpected(XmlDictionaryReader reader, string expected, char found) + //{ + // ThrowXmlException(reader, SR.XmlTokenExpected, expected, found.ToString()); + //} + + //public static void ThrowTokenExpected(XmlDictionaryReader reader, string expected, string found) + //{ + // ThrowXmlException(reader, SR.XmlTokenExpected, expected, found); + //} + + //public static void ThrowInvalidCharRef(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlInvalidCharRef); + //} + + //public static void ThrowTagMismatch(XmlDictionaryReader reader, string expectedPrefix, string expectedLocalName, string foundPrefix, string foundLocalName) + //{ + // ThrowXmlException(reader, SR.XmlTagMismatch, GetName(expectedPrefix, expectedLocalName), GetName(foundPrefix, foundLocalName)); + //} + + //public static void ThrowDuplicateXmlnsAttribute(XmlDictionaryReader reader, string localName, string ns) + //{ + // string name; + // if (localName.Length == 0) + // { + // name = "xmlns"; + // } + // else + // { + // name = "xmlns:" + localName; + // } + + // ThrowXmlException(reader, SR.XmlDuplicateAttribute, name, name, ns); + //} + + //public static void ThrowDuplicateAttribute(XmlDictionaryReader reader, string prefix1, string prefix2, string localName, string ns) + //{ + // ThrowXmlException(reader, SR.XmlDuplicateAttribute, GetName(prefix1, localName), GetName(prefix2, localName), ns); + //} + + //public static void ThrowInvalidBinaryFormat(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlInvalidFormat); + //} + + //public static void ThrowInvalidRootData(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlInvalidRootData); + //} + + //public static void ThrowMultipleRootElements(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlMultipleRootElements); + //} + + //public static void ThrowDeclarationNotFirst(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlDeclNotFirst); + //} + + //public static void ThrowConversionOverflow(XmlDictionaryReader reader, string value, string type) + //{ + // ThrowXmlException(reader, SR.XmlConversionOverflow, value, type); + //} + + //public static void ThrowXmlDictionaryStringIDOutOfRange(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlDictionaryStringIDRange, XmlDictionaryString.MinKey.ToString(NumberFormatInfo.CurrentInfo), XmlDictionaryString.MaxKey.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowXmlDictionaryStringIDUndefinedStatic(XmlDictionaryReader reader, int key) + //{ + // ThrowXmlException(reader, SR.XmlDictionaryStringIDUndefinedStatic, key.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowXmlDictionaryStringIDUndefinedSession(XmlDictionaryReader reader, int key) + //{ + // ThrowXmlException(reader, SR.XmlDictionaryStringIDUndefinedSession, key.ToString(NumberFormatInfo.CurrentInfo)); + //} + + //public static void ThrowEmptyNamespace(XmlDictionaryReader reader) + //{ + // ThrowXmlException(reader, SR.XmlEmptyNamespaceRequiresNullPrefix); + //} + + public static XmlException CreateConversionException(string value, string type, Exception exception) + { + return new XmlException(SR.Format(SR.XmlInvalidConversion, value, type), exception); + } + + public static XmlException CreateEncodingException(byte[] buffer, int offset, int count, Exception exception) + { + return CreateEncodingException(new System.Text.UTF8Encoding(false, false).GetString(buffer, offset, count), exception); + } + + public static XmlException CreateEncodingException(string value, Exception exception) + { + return new XmlException(SR.Format(SR.XmlInvalidUTF8Bytes, value), exception); + } + } +} diff --git a/Compat.Private.Serialization/Resources/Common/SR.Designer.cs b/Compat.Private.Serialization/Resources/Common/SR.Designer.cs new file mode 100644 index 0000000..8b5ef21 --- /dev/null +++ b/Compat.Private.Serialization/Resources/Common/SR.Designer.cs @@ -0,0 +1,3996 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Compat { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal partial class SR { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal SR() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Resources.SR", typeof(SR).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to The element cannot have 'abstract' set to 'true'.. + /// + internal static string AbstractElementNotSupported { + get { + return ResourceManager.GetString("AbstractElementNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type cannot have 'abstract' set to 'true'.. + /// + internal static string AbstractTypeNotSupported { + get { + return ResourceManager.GetString("AbstractTypeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of referenced collection types contains more than one type with same data contract name. Include only one of the following types. Only matching types can be valid references: {0}. + /// + internal static string AmbiguousReferencedCollectionTypes1 { + get { + return ResourceManager.GetString("AmbiguousReferencedCollectionTypes1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of referenced collection types contains more than one type with data contract name '{0}' in namespace '{1}'. Include only one of the following types. Only matching types can be valid references: {2}. + /// + internal static string AmbiguousReferencedCollectionTypes3 { + get { + return ResourceManager.GetString("AmbiguousReferencedCollectionTypes3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of referenced types contains more than one type with same data contract name. Need to exclude all but one of the following types. Only matching types can be valid references: {0}. + /// + internal static string AmbiguousReferencedTypes1 { + get { + return ResourceManager.GetString("AmbiguousReferencedTypes1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of referenced types contains more than one type with data contract name '{0}' in namespace '{1}'. Need to exclude all but one of the following types. Only matching types can be valid references: {2}. + /// + internal static string AmbiguousReferencedTypes3 { + get { + return ResourceManager.GetString("AmbiguousReferencedTypes3", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid '{0}' annotation in type '{1}' from namespace '{2}'. Attribute '{3}' not present.. + /// + internal static string AnnotationAttributeNotFound { + get { + return ResourceManager.GetString("AnnotationAttributeNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anonymous type in element '{0}' from namespace '{1}' is not supported.. + /// + internal static string AnonymousTypeNotSupported { + get { + return ResourceManager.GetString("AnonymousTypeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'anyAttribute' is not supported.. + /// + internal static string AnyAttributeNotSupported { + get { + return ResourceManager.GetString("AnyAttributeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array length '{0}' provided by the get-only collection of type '{1}' is less than the number of array elements found in the input stream. Consider increasing the length of the array.. + /// + internal static string ArrayExceededSize { + get { + return ResourceManager.GetString("ArrayExceededSize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array length '{0}' provided by Size attribute is not equal to the number of array elements '{1}' from namespace '{2}' found.. + /// + internal static string ArrayExceededSizeAttribute { + get { + return ResourceManager.GetString("ArrayExceededSizeAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Form for element '{0}' must be qualified.. + /// + internal static string ArrayItemFormMustBe { + get { + return ResourceManager.GetString("ArrayItemFormMustBe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array Size '{0}' is not equal to the number of elements found '{1}'.. + /// + internal static string ArraySizeAttributeIncorrect { + get { + return ResourceManager.GetString("ArraySizeAttributeIncorrect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array type '{0}' in namespace '{1}' cannot be imported. {2}. + /// + internal static string ArrayTypeCannotBeImported { + get { + return ResourceManager.GetString("ArrayTypeCannotBeImported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ArrayTypeIsNotSupported: {0}. + /// + internal static string ArrayTypeIsNotSupported { + get { + return ResourceManager.GetString("ArrayTypeIsNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. '{0}[]' is not supported when generating code for serialization.. + /// + internal static string ArrayTypeIsNotSupported_GeneratingCode { + get { + return ResourceManager.GetString("ArrayTypeIsNotSupported_GeneratingCode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assembly '{0}' is not found.. + /// + internal static string AssemblyNotFound { + get { + return ResourceManager.GetString("AssemblyNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot inherit from a type that is not marked with DataContractAttribute or SerializableAttribute. Consider marking the base type '{1}' with DataContractAttribute or SerializableAttribute, or removing them from the derived type.. + /// + internal static string AttributedTypesCannotInheritFromNonAttributedSerializableTypes { + get { + return ResourceManager.GetString("AttributedTypesCannotInheritFromNonAttributedSerializableTypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML '{2}' '{3}:{4}' does not contain expected attribute '{0}:{1}'. The deserializer has no knowledge of which type to deserialize. Check that the type being serialized has the same contract as the type being deserialized.. + /// + internal static string AttributeNotFound { + get { + return ResourceManager.GetString("AttributeNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to One of its base types, '{0}' from namespace '{1}' is not ISerializable.. + /// + internal static string BaseTypeNotISerializable { + get { + return ResourceManager.GetString("BaseTypeNotISerializable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serialization Callback '{1}' in type '{0}' must return void. . + /// + internal static string CallbackMustReturnVoid { + get { + return ResourceManager.GetString("CallbackMustReturnVoid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'. . + /// + internal static string CallbackParameterInvalid { + get { + return ResourceManager.GetString("CallbackParameterInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute. . + /// + internal static string CallbacksCannotBeVirtualMethods { + get { + return ResourceManager.GetString("CallbacksCannotBeVirtualMethods", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A unique name cannot be computed for '{0}' because there are already Int32.MaxValue types of with the same name.. + /// + internal static string CannotComputeUniqueName { + get { + return ResourceManager.GetString("CannotComputeUniqueName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot deserialize since root element references unrecognized object with id '{0}'.. + /// + internal static string CannotDeserializeRefAtTopLevel { + get { + return ResourceManager.GetString("CannotDeserializeRefAtTopLevel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot export null assembly provided via '{0}' parameter.. + /// + internal static string CannotExportNullAssembly { + get { + return ResourceManager.GetString("CannotExportNullAssembly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot export null type provided via KnownTypesCollection.. + /// + internal static string CannotExportNullKnownType { + get { + return ResourceManager.GetString("CannotExportNullKnownType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot export null type provided via '{0}' parameter.. + /// + internal static string CannotExportNullType { + get { + return ResourceManager.GetString("CannotExportNullType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type contains two attributes with the same name '{0}'. Multiple attributes with the same name in one type are not supported.. + /// + internal static string CannotHaveDuplicateAttributeNames { + get { + return ResourceManager.GetString("CannotHaveDuplicateAttributeNames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type contains two elements with the same name '{0}'. Multiple elements with the same name in one type are not supported because members marked with DataMemberAttribute attribute must have unique names.. + /// + internal static string CannotHaveDuplicateElementNames { + get { + return ResourceManager.GetString("CannotHaveDuplicateElementNames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot import invalid schemas. Compilation on the XmlSchemaSet failed.. + /// + internal static string CannotImportInvalidSchemas { + get { + return ResourceManager.GetString("CannotImportInvalidSchemas", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot import type for null XmlQualifiedName specified via parameter.. + /// + internal static string CannotImportNullDataContractName { + get { + return ResourceManager.GetString("CannotImportNullDataContractName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot import null XmlSchema contained in XmlSchemaSet specified via parameter.. + /// + internal static string CannotImportNullSchema { + get { + return ResourceManager.GetString("CannotImportNullSchema", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot load member type '{0}'.. + /// + internal static string CannotLoadMemberType { + get { + return ResourceManager.GetString("CannotLoadMemberType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Object graph for type '{0}' contains cycles and cannot be serialized if references are not tracked. Consider using the DataContractAttribute with the IsReference property set to true.. + /// + internal static string CannotSerializeObjectWithCycles { + get { + return ResourceManager.GetString("CannotSerializeObjectWithCycles", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. Data can only be stored into ArgBuilder or LocalBuilder. Got: {0}.. + /// + internal static string CanOnlyStoreIntoArgOrLocGot0 { + get { + return ResourceManager.GetString("CanOnlyStoreIntoArgOrLocGot0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContractJsonSerializer does not support the setting of the FullTypeName of the object to be serialized to a value other than the default FullTypeName. Attempted to serialize object with full type name '{0}' and default full type name '{1}'.. + /// + internal static string ChangingFullTypeNameNotSupported { + get { + return ResourceManager.GetString("ChangingFullTypeNameNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. Char is not a valid schema primitive and should be treated as int in DataContract.. + /// + internal static string CharIsInvalidPrimitive { + get { + return ResourceManager.GetString("CharIsInvalidPrimitive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ClassDataContractReturnedForGetOnlyCollection: {0}. + /// + internal static string ClassDataContractReturnedForGetOnlyCollection { + get { + return ResourceManager.GetString("ClassDataContractReturnedForGetOnlyCollection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The deserializer cannot load the type to deserialize because type '{1}' could not be found in assembly '{0}'. Check that the type being serialized has the same contract as the type being deserialized and the same assembly is used.. + /// + internal static string ClrTypeNotFound { + get { + return ResourceManager.GetString("ClrTypeNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is a collection type and cannot be serialized when assigned to an interface type that does not implement IEnumerable ('{1}'.). + /// + internal static string CollectionAssignedToIncompatibleInterface { + get { + return ResourceManager.GetString("CollectionAssignedToIncompatibleInterface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection type '{0}' does not have a valid Add method.. + /// + internal static string CollectionMustHaveAddMethod { + get { + return ResourceManager.GetString("CollectionMustHaveAddMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection type '{0}' does not have a valid GetEnumerator method.. + /// + internal static string CollectionMustHaveGetEnumeratorMethod { + get { + return ResourceManager.GetString("CollectionMustHaveGetEnumeratorMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection type '{0}' must have a non-null item type.. + /// + internal static string CollectionMustHaveItemType { + get { + return ResourceManager.GetString("CollectionMustHaveItemType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is a built-in type and cannot be a collection.. + /// + internal static string CollectionTypeCannotBeBuiltIn { + get { + return ResourceManager.GetString("CollectionTypeCannotBeBuiltIn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has DataContractAttribute attribute.. + /// + internal static string CollectionTypeCannotHaveDataContract { + get { + return ResourceManager.GetString("CollectionTypeCannotHaveDataContract", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} does not have a valid Add method with parameter of type '{1}'.. + /// + internal static string CollectionTypeDoesNotHaveAddMethod { + get { + return ResourceManager.GetString("CollectionTypeDoesNotHaveAddMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} does not have a default constructor.. + /// + internal static string CollectionTypeDoesNotHaveDefaultCtor { + get { + return ResourceManager.GetString("CollectionTypeDoesNotHaveDefaultCtor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has multiple definitions of interface '{1}'.. + /// + internal static string CollectionTypeHasMultipleDefinitionsOfInterface { + get { + return ResourceManager.GetString("CollectionTypeHasMultipleDefinitionsOfInterface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} does not implement IEnumerable interface.. + /// + internal static string CollectionTypeIsNotIEnumerable { + get { + return ResourceManager.GetString("CollectionTypeIsNotIEnumerable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The combined length of the prefix and namespace must not be greater than {0}.. + /// + internal static string CombinedPrefixNSLength { + get { + return ResourceManager.GetString("CombinedPrefixNSLength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Complex types derived by restriction not supported. . + /// + internal static string ComplexTypeRestrictionNotSupported { + get { + return ResourceManager.GetString("ComplexTypeRestrictionNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. Could not load serialization schema. Consider providing schema with namespace '{0}'.. + /// + internal static string CouldNotReadSerializationSchema { + get { + return ResourceManager.GetString("CouldNotReadSerializationSchema", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. DataContract cache overflow.. + /// + internal static string DataContractCacheOverflow { + get { + return ResourceManager.GetString("DataContractCacheOverflow", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ContractNamespaceAttribute attribute maps CLR namespace '{2}' to multiple data contract namespaces '{0}' and '{1}'. You can map a CLR namespace to only one data contract namespace.. + /// + internal static string DataContractNamespaceAlreadySet { + get { + return ResourceManager.GetString("DataContractNamespaceAlreadySet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContract namespace '{0}' is not a valid URI.. + /// + internal static string DataContractNamespaceIsNotValid { + get { + return ResourceManager.GetString("DataContractNamespaceIsNotValid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContract namespace '{0}' cannot be specified since it is reserved.. + /// + internal static string DataContractNamespaceReserved { + get { + return ResourceManager.GetString("DataContractNamespaceReserved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member '{0}.{1}' has DataMemberAttribute attribute. Use EnumMemberAttribute attribute instead.. + /// + internal static string DataMemberOnEnumField { + get { + return ResourceManager.GetString("DataMemberOnEnumField", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Element '{2}:{3}' contains data of the '{0}:{1}' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to '{1}' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.. + /// + internal static string DcTypeNotFoundOnDeserialize { + get { + return ResourceManager.GetString("DcTypeNotFoundOnDeserialize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' with data contract name '{1}:{2}' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.. + /// + internal static string DcTypeNotFoundOnSerialize { + get { + return ResourceManager.GetString("DcTypeNotFoundOnSerialize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Element '{2}:{3}' contains data from a type that maps to the name '{0}:{1}'. The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name '{1}' and namespace '{0}'.. + /// + internal static string DcTypeNotResolvedOnDeserialize { + get { + return ResourceManager.GetString("DcTypeNotResolvedOnDeserialize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default value on element '{0}' is not supported.. + /// + internal static string DefaultOnElementNotSupported { + get { + return ResourceManager.GetString("DefaultOnElementNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is not ISerializable but its base type '{0}' in namespace '{1}' is ISerializable.. + /// + internal static string DerivedTypeNotISerializable { + get { + return ResourceManager.GetString("DerivedTypeNotISerializable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deserialized object with reference id '{0}' not found in stream.. + /// + internal static string DeserializedObjectWithIdNotFound { + get { + return ResourceManager.GetString("DeserializedObjectWithIdNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContract with name '{0}' and namespace '{1}' cannot be added to DataContractSet since another contract with the same data contract name is already present and the contracts are not equivalent.. + /// + internal static string DupContractInDataContractSet { + get { + return ResourceManager.GetString("DupContractInDataContractSet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be added to list of known types since another type '{1}' with the same data contract name '{2}:{3}' is already present.. + /// + internal static string DupContractInKnownTypes { + get { + return ResourceManager.GetString("DupContractInKnownTypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{2}' contains two members '{0}' 'and '{1}' with the same name '{3}'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using EnumMemberAttribute attribute.. + /// + internal static string DupEnumMemberValue { + get { + return ResourceManager.GetString("DupEnumMemberValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The collection data contract type '{0}' specifies the same value '{1}' for both the KeyName and the ValueName properties. This is not allowed. Consider changing either the KeyName or the ValueName property.. + /// + internal static string DupKeyValueName { + get { + return ResourceManager.GetString("DupKeyValueName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'. . + /// + internal static string DuplicateAttribute { + get { + return ResourceManager.GetString("DuplicateAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'. . + /// + internal static string DuplicateCallback { + get { + return ResourceManager.GetString("DuplicateCallback", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid IExtensibleDataObject. Both '{0}' and '{1}' in type '{2}' provide property setter.. + /// + internal static string DuplicateExtensionDataSetMethod { + get { + return ResourceManager.GetString("DuplicateExtensionDataSetMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{2}' contains two members '{0}' 'and '{1}' with the same data member name '{3}'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using DataMemberAttribute attribute.. + /// + internal static string DupMemberName { + get { + return ResourceManager.GetString("DupMemberName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContract for type '{0}' cannot be added to DataContractSet since type '{1}' with the same data contract name '{2}' in namespace '{3}' is already present and the contracts are not equivalent.. + /// + internal static string DupTypeContractInDataContractSet { + get { + return ResourceManager.GetString("DupTypeContractInDataContractSet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'maxOccurs' on element '{0}' must be 1.. + /// + internal static string ElementMaxOccursMustBe { + get { + return ResourceManager.GetString("ElementMaxOccursMustBe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'minOccurs' on element '{0}' must be 0 or 1.. + /// + internal static string ElementMinOccursMustBe { + get { + return ResourceManager.GetString("ElementMinOccursMustBe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ref to element '{0}' in '{1}' namespace is not supported.. + /// + internal static string ElementRefOnLocalElementNotSupported { + get { + return ResourceManager.GetString("ElementRefOnLocalElementNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}. Encountered '{1}' with name '{2}', namespace '{3}'.. + /// + internal static string EncounteredWithNameNamespace { + get { + return ResourceManager.GetString("EncounteredWithNameNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enumeration facets without 'value' are not supported.. + /// + internal static string EnumEnumerationFacetsMustHaveValue { + get { + return ResourceManager.GetString("EnumEnumerationFacetsMustHaveValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anonymous type with <list> cannot be used to create Flags enumeration because it is not a valid enum type.. + /// + internal static string EnumListInAnonymousTypeNotSupported { + get { + return ResourceManager.GetString("EnumListInAnonymousTypeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Simple type list must contain an anonymous type specifying enumeration facets.. + /// + internal static string EnumListMustContainAnonymousType { + get { + return ResourceManager.GetString("EnumListMustContainAnonymousType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Facets other than enumeration facets are not supported.. + /// + internal static string EnumOnlyEnumerationFacetsSupported { + get { + return ResourceManager.GetString("EnumOnlyEnumerationFacetsSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anonymous type with <restriction> cannot be used to create Flags enumeration because it is not a valid enum type.. + /// + internal static string EnumRestrictionInvalid { + get { + return ResourceManager.GetString("EnumRestrictionInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enum type '{0}' in namespace '{1}' cannot be imported. {2}. + /// + internal static string EnumTypeCannotBeImported { + get { + return ResourceManager.GetString("EnumTypeCannotBeImported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enum type '{0}' cannot have the IsReference setting of '{1}'. Either change the setting to '{2}', or remove it completely.. + /// + internal static string EnumTypeCannotHaveIsReference { + get { + return ResourceManager.GetString("EnumTypeCannotHaveIsReference", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContractJsonSerializer does not support data members of type '{0}'. Consider using int, System.Object, or a concrete enum definition instead.. + /// + internal static string EnumTypeNotSupportedByDataContractJsonSerializer { + get { + return ResourceManager.GetString("EnumTypeNotSupportedByDataContractJsonSerializer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Anonymous type with <union>. cannot be used to create Flags enumeration because it is not a valid enum type.. + /// + internal static string EnumUnionInAnonymousTypeNotSupported { + get { + return ResourceManager.GetString("EnumUnionInAnonymousTypeNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error deserializing the object {0}. {1}. + /// + internal static string ErrorDeserializing { + get { + return ResourceManager.GetString("ErrorDeserializing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error in line {0} position {1}.. + /// + internal static string ErrorInLine { + get { + return ResourceManager.GetString("ErrorInLine", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error checking start element of object {0}. {1}. + /// + internal static string ErrorIsStartObject { + get { + return ResourceManager.GetString("ErrorIsStartObject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error serializing the object {0}. {1}. + /// + internal static string ErrorSerializing { + get { + return ResourceManager.GetString("ErrorSerializing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to of type {0}. + /// + internal static string ErrorTypeInfo { + get { + return ResourceManager.GetString("ErrorTypeInfo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error writing end element of object {0}. {1}. + /// + internal static string ErrorWriteEndObject { + get { + return ResourceManager.GetString("ErrorWriteEndObject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There was an error writing start element of object {0}. {1}. + /// + internal static string ErrorWriteStartObject { + get { + return ResourceManager.GetString("ErrorWriteStartObject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maximum number of items that can be serialized or deserialized in an object graph is '{0}'.. + /// + internal static string ExceededMaxItemsQuota { + get { + return ResourceManager.GetString("ExceededMaxItemsQuota", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expecting element '{1}' from namespace '{0}'.. + /// + internal static string ExpectingElement { + get { + return ResourceManager.GetString("ExpectingElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expecting state '{0}' when ReadObject is called.. + /// + internal static string ExpectingElementAtDeserialize { + get { + return ResourceManager.GetString("ExpectingElementAtDeserialize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expecting End'{0}'.. + /// + internal static string ExpectingEnd { + get { + return ResourceManager.GetString("ExpectingEnd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expecting state '{0}'.. + /// + internal static string ExpectingState { + get { + return ResourceManager.GetString("ExpectingState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IExtensibleDataObject property setter '{1}' in type '{0}' must return void.. + /// + internal static string ExtensionDataSetMustReturnVoid { + get { + return ResourceManager.GetString("ExtensionDataSetMustReturnVoid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IExtensibleDataObject property setter '{1}' in type '{0}' must have a single parameter of type '{2}'.. + /// + internal static string ExtensionDataSetParameterInvalid { + get { + return ResourceManager.GetString("ExtensionDataSetParameterInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Object graph of type '{0}' with Id '{2}' contains a reference to itself. The object has been replaced with a new object of type '{1}' either because it implements IObjectReference or because it is surrogated. The serializer does not support fixing up the nested reference to the new object and cannot deserialize this object. Consider changing the object to remove the nested self-reference.. + /// + internal static string FactoryObjectContainsSelfReference { + get { + return ResourceManager.GetString("FactoryObjectContainsSelfReference", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Factory type '{0}' for ISerializable type '{1}' must also be ISerializable.. + /// + internal static string FactoryTypeNotISerializable { + get { + return ResourceManager.GetString("FactoryTypeNotISerializable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to create Delegate for method '{0}' of type '{1}'.. + /// + internal static string FailedToCreateMethodDelegate { + get { + return ResourceManager.GetString("FailedToCreateMethodDelegate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fixed value on element '{0}' is not supported.. + /// + internal static string FixedOnElementNotSupported { + get { + return ResourceManager.GetString("FixedOnElementNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Form on element '{0}' must be qualified.. + /// + internal static string FormMustBeQualified { + get { + return ResourceManager.GetString("FormMustBeQualified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Annotation for generic type '{0}' did not have attribute '{1}'.. + /// + internal static string GenericAnnotationAttributeNotFound { + get { + return ResourceManager.GetString("GenericAnnotationAttributeNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nested level on annotation elements '{0}' from namespace '{1}' for generic type '{2}' must be in increasing order.. + /// + internal static string GenericAnnotationForNestedLevelMustBeIncreasing { + get { + return ResourceManager.GetString("GenericAnnotationForNestedLevelMustBeIncreasing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Annotation element '{0}' from namespace '{1}' for generic type '{2}' has an invalid value '{3}' for attribute '{4}'. Expecting value to be of type '{5}'.. + /// + internal static string GenericAnnotationHasInvalidAttributeValue { + get { + return ResourceManager.GetString("GenericAnnotationHasInvalidAttributeValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Annotation for generic type '{2}' has an invalid element '{0}' from namespace '{1}'.. + /// + internal static string GenericAnnotationHasInvalidElement { + get { + return ResourceManager.GetString("GenericAnnotationHasInvalidElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A user callback threw an exception. Check the exception stack and inner exception to determine the callback that failed.. + /// + internal static string GenericCallbackException { + get { + return ResourceManager.GetString("GenericCallbackException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract name '{0}' for type '{1}' has a curly brace '{{' that is not matched with a closing curly brace. Curly braces have special meaning in data contract names - they are used to customize the naming of data contracts for generic types.. + /// + internal static string GenericNameBraceMismatch { + get { + return ResourceManager.GetString("GenericNameBraceMismatch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In the data contract name for type '{1}', there are curly braces with '{0}' inside, which is an invalid value. Curly braces have special meaning in data contract names - they are used to customize the naming of data contracts for generic types. Based on the number of generic parameters this type has, the contents of the curly braces must either be a number between 0 and '{2}' to insert the name of the generic parameter at that index or the '#' symbol to insert a digest of the generic parameter namespaces.. + /// + internal static string GenericParameterNotValid { + get { + return ResourceManager.GetString("GenericParameterNotValid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types.. + /// + internal static string GenericTypeNotExportable { + get { + return ResourceManager.GetString("GenericTypeNotExportable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection interface type '{0}' is being used as a get-only property and does not have an Add method. Consider adding a setter to the property or using a collection data contract that does have an Add method - for example IList or ICollection<T>.. + /// + internal static string GetOnlyCollectionMustHaveAddMethod { + get { + return ResourceManager.GetString("GetOnlyCollectionMustHaveAddMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to GetRealObjectReturnedNull: {0}. + /// + internal static string GetRealObjectReturnedNull { + get { + return ResourceManager.GetString("GetRealObjectReturnedNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The IsReference setting for type '{0}' is '{1}', but the same setting for its parent class '{2}' is '{3}'. Derived types must have the same value for IsReference as the base type. Change the setting on type '{0}' to '{3}', or on type '{2}' to '{1}', or do not set IsReference explicitly.. + /// + internal static string InconsistentIsReference { + get { + return ResourceManager.GetString("InconsistentIsReference", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Property '{1}' in type '{0}' cannot be serialized because serialization of indexed properties is not supported.. + /// + internal static string IndexedPropertyCannotBeSerialized { + get { + return ResourceManager.GetString("IndexedPropertyCannotBeSerialized", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Interface type '{0}' cannot be created. Consider replacing with a non-interface serializable type.. + /// + internal static string InterfaceTypeCannotBeCreated { + get { + return ResourceManager.GetString("InterfaceTypeCannotBeCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Annotation '{0}' from namespace '{1}' has an invalid element '{2}' from namespace '{3}'. Expecting text.. + /// + internal static string InvalidAnnotationExpectingText { + get { + return ResourceManager.GetString("InvalidAnnotationExpectingText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid assembly format: {0}. + /// + internal static string InvalidAssemblyFormat { + get { + return ResourceManager.GetString("InvalidAssemblyFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered invalid character '{0}'.. + /// + internal static string InvalidCharacterEncountered { + get { + return ResourceManager.GetString("InvalidCharacterEncountered", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' in namespace '{1}' cannot be used as the base type of a data contract type, because it itself does not have a data contract. Consider marking type '{0}' with the DataContractAttribute attribute.. + /// + internal static string InvalidClassDerivation { + get { + return ResourceManager.GetString("InvalidClassDerivation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have CollectionDataContractAttribute attribute ItemName set to null or empty string.. + /// + internal static string InvalidCollectionContractItemName { + get { + return ResourceManager.GetString("InvalidCollectionContractItemName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have CollectionDataContractAttribute attribute KeyName set to null or empty string.. + /// + internal static string InvalidCollectionContractKeyName { + get { + return ResourceManager.GetString("InvalidCollectionContractKeyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The collection data contract type '{0}' specifies '{1}' for the KeyName property. This is not allowed since the type is not IDictionary. Remove the setting for the KeyName property.. + /// + internal static string InvalidCollectionContractKeyNoDictionary { + get { + return ResourceManager.GetString("InvalidCollectionContractKeyNoDictionary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have CollectionDataContractAttribute attribute Name set to null or empty string.. + /// + internal static string InvalidCollectionContractName { + get { + return ResourceManager.GetString("InvalidCollectionContractName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have CollectionDataContractAttribute attribute Namespace set to null.. + /// + internal static string InvalidCollectionContractNamespace { + get { + return ResourceManager.GetString("InvalidCollectionContractNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have CollectionDataContractAttribute attribute ValueName set to null or empty string.. + /// + internal static string InvalidCollectionContractValueName { + get { + return ResourceManager.GetString("InvalidCollectionContractValueName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The collection data contract type '{0}' specifies '{1}' for the ValueName property. This is not allowed since the type is not IDictionary. Remove the setting for the ValueName property.. + /// + internal static string InvalidCollectionContractValueNoDictionary { + get { + return ResourceManager.GetString("InvalidCollectionContractValueNoDictionary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' with CollectionDataContractAttribute attribute is an invalid collection type since it. + /// + internal static string InvalidCollectionDataContract { + get { + return ResourceManager.GetString("InvalidCollectionDataContract", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' is an invalid collection type since it. + /// + internal static string InvalidCollectionType { + get { + return ResourceManager.GetString("InvalidCollectionType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have DataContractAttribute attribute Name set to null or empty string.. + /// + internal static string InvalidDataContractName { + get { + return ResourceManager.GetString("InvalidDataContractName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have DataContractAttribute attribute Namespace set to null.. + /// + internal static string InvalidDataContractNamespace { + get { + return ResourceManager.GetString("InvalidDataContractNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member '{0}' in type '{1}' cannot have DataMemberAttribute attribute Name set to null or empty string.. + /// + internal static string InvalidDataMemberName { + get { + return ResourceManager.GetString("InvalidDataMemberName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to InvalidDataNode: {0}. + /// + internal static string InvalidDataNode { + get { + return ResourceManager.GetString("InvalidDataNode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Annotation for element {0} in type {1} from namespace {2} specifies EmitDefaultValue as 'true'. This requires the element to be either nillable or the element's type must be a value type.. + /// + internal static string InvalidEmitDefaultAnnotation { + get { + return ResourceManager.GetString("InvalidEmitDefaultAnnotation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to InvalidEnumBaseType: {0}, {1}, {2}, {3}. + /// + internal static string InvalidEnumBaseType { + get { + return ResourceManager.GetString("InvalidEnumBaseType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' in type '{1}' cannot have EnumMemberAttribute attribute Value set to null or empty string.. + /// + internal static string InvalidEnumMemberValue { + get { + return ResourceManager.GetString("InvalidEnumMemberValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid enum value '{0}' cannot be deserialized into type '{1}'. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.. + /// + internal static string InvalidEnumValueOnRead { + get { + return ResourceManager.GetString("InvalidEnumValueOnRead", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enum value '{0}' is invalid for type '{1}' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.. + /// + internal static string InvalidEnumValueOnWrite { + get { + return ResourceManager.GetString("InvalidEnumValueOnWrite", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot have MethodName on XmlSchemaProviderAttribute attribute set to null or empty string. . + /// + internal static string InvalidGetSchemaMethod { + get { + return ResourceManager.GetString("InvalidGetSchemaMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CLR namespace '{0}' cannot have ContractNamespace set to null.. + /// + internal static string InvalidGlobalDataContractNamespace { + get { + return ResourceManager.GetString("InvalidGlobalDataContractNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The inclusive namespace prefix collection cannot contain null as one of the items.. + /// + internal static string InvalidInclusivePrefixListCollection { + get { + return ResourceManager.GetString("InvalidInclusivePrefixListCollection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot import type '{0}' in namespace '{1}' as its base type because derived type is ISerializable but the base type is not ISerializable.. + /// + internal static string InvalidISerializableDerivation { + get { + return ResourceManager.GetString("InvalidISerializableDerivation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is an invalid dictionary type. Element '{0}' must reference a complex type containing a sequence with two required elements. Either fix the schema or remove the IsDictionary annotation.. + /// + internal static string InvalidKeyValueType { + get { + return ResourceManager.GetString("InvalidKeyValueType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It is an invalid dictionary type since element '{0}' references a type from a different namespace '{1}'. Either fix the schema or remove the IsDictionary annotation.. + /// + internal static string InvalidKeyValueTypeNamespace { + get { + return ResourceManager.GetString("InvalidKeyValueTypeNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The empty string is not a valid local name.. + /// + internal static string InvalidLocalNameEmpty { + get { + return ResourceManager.GetString("InvalidLocalNameEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member '{0}.{1}' cannot be serialized since it is neither a field nor a property, and therefore cannot be marked with the DataMemberAttribute attribute. Remove the DataMemberAttribute attribute from the '{1}' member.. + /// + internal static string InvalidMember { + get { + return ResourceManager.GetString("InvalidMember", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}.{1}()' returns a non-null value. The return value must be null since IsAny. + /// + internal static string InvalidNonNullReturnValueByIsAny { + get { + return ResourceManager.GetString("InvalidNonNullReturnValueByIsAny", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to InvalidPrimitiveType: {0}. + /// + internal static string InvalidPrimitiveType { + get { + return ResourceManager.GetString("InvalidPrimitiveType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' is not a valid serializable type.. + /// + internal static string InvalidPrimitiveType_Serialization { + get { + return ResourceManager.GetString("InvalidPrimitiveType_Serialization", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}.GetSchema()' must return a schema with a valid Id.. + /// + internal static string InvalidReturnSchemaOnGetSchemaMethod { + get { + return ResourceManager.GetString("InvalidReturnSchemaOnGetSchemaMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}.{1}()' returns '{2}'. The return type must be compatible with '{3}'.. + /// + internal static string InvalidReturnTypeOnGetSchemaMethod { + get { + return ResourceManager.GetString("InvalidReturnTypeOnGetSchemaMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Size '{0}'. Must be non-negative integer.. + /// + internal static string InvalidSizeDefinition { + get { + return ResourceManager.GetString("InvalidSizeDefinition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. ExtensionDataReader is in an invalid state.. + /// + internal static string InvalidStateInExtensionDataReader { + get { + return ResourceManager.GetString("InvalidStateInExtensionDataReader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML data contract Name for type '{0}' cannot be set to null or empty string.. + /// + internal static string InvalidXmlDataContractName { + get { + return ResourceManager.GetString("InvalidXmlDataContractName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The XML encountered when deserializing extension data is invalid.. + /// + internal static string InvalidXmlDeserializingExtensionData { + get { + return ResourceManager.GetString("InvalidXmlDeserializingExtensionData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Id '{0}'. Must not be null or empty.. + /// + internal static string InvalidXsIdDefinition { + get { + return ResourceManager.GetString("InvalidXsIdDefinition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid Ref '{0}'. Must not be null or empty.. + /// + internal static string InvalidXsRefDefinition { + get { + return ResourceManager.GetString("InvalidXsRefDefinition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A null value cannot be serialized at the top level for IXmlSerializable root type '{0}' since its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct.. + /// + internal static string IsAnyCannotBeNull { + get { + return ResourceManager.GetString("IsAnyCannotBeNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An object of type '{0}' cannot be serialized at the top level for IXmlSerializable root type '{1}' since its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct.. + /// + internal static string IsAnyCannotBeSerializedAsDerivedType { + get { + return ResourceManager.GetString("IsAnyCannotBeSerializedAsDerivedType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot specify an XmlRootAttribute attribute because its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct.. + /// + internal static string IsAnyCannotHaveXmlRoot { + get { + return ResourceManager.GetString("IsAnyCannotHaveXmlRoot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IsAny not supported by NetDataContractSerializer: {0}. + /// + internal static string IsAnyNotSupportedByNetDataContractSerializer { + get { + return ResourceManager.GetString("IsAnyNotSupportedByNetDataContractSerializer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is an invalid value for IsDictionary annotation. {1}. + /// + internal static string IsDictionaryFormattedIncorrectly { + get { + return ResourceManager.GetString("IsDictionaryFormattedIncorrectly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' has set its ISerializable assembly name to "0". "0" is an invalid assembly name. Consider using the full name of mscorlib if you would like your type to be deserialized in that assembly.. + /// + internal static string ISerializableAssemblyNameSetToZero { + get { + return ResourceManager.GetString("ISerializableAssemblyNameSetToZero", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be ISerializable and have DataContractAttribute attribute.. + /// + internal static string ISerializableCannotHaveDataContract { + get { + return ResourceManager.GetString("ISerializableCannotHaveDataContract", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Its root sequence contains more than one particle.. + /// + internal static string ISerializableContainsMoreThanOneItems { + get { + return ResourceManager.GetString("ISerializableContainsMoreThanOneItems", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Derived ISerializable types cannot contain any particles.. + /// + internal static string ISerializableDerivedContainsOneOrMoreItems { + get { + return ResourceManager.GetString("ISerializableDerivedContainsOneOrMoreItems", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It does not contain root sequence with a wildcard element <any>.. + /// + internal static string ISerializableDoesNotContainAny { + get { + return ResourceManager.GetString("ISerializableDoesNotContainAny", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It does not reference attribute '{0}' from namespace '{1}'. . + /// + internal static string ISerializableMustRefFactoryTypeAttribute { + get { + return ResourceManager.GetString("ISerializableMustRefFactoryTypeAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ISerializable type '{0}' in namespace '{1}' cannot be imported. '{2}'. + /// + internal static string ISerializableTypeCannotBeImported { + get { + return ResourceManager.GetString("ISerializableTypeCannotBeImported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'maxOccurs' on the wildcard element must be '{0}'.. + /// + internal static string ISerializableWildcardMaxOccursMustBe { + get { + return ResourceManager.GetString("ISerializableWildcardMaxOccursMustBe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'minOccurs' on the wildcard element must be '{0}'.. + /// + internal static string ISerializableWildcardMinOccursMustBe { + get { + return ResourceManager.GetString("ISerializableWildcardMinOccursMustBe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Namespace on the wildcard element must be '{0}'.. + /// + internal static string ISerializableWildcardNamespaceInvalid { + get { + return ResourceManager.GetString("ISerializableWildcardNamespaceInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ProcessContents on the wildcard element must be '{0}'.. + /// + internal static string ISerializableWildcardProcessContentsInvalid { + get { + return ResourceManager.GetString("ISerializableWildcardProcessContentsInvalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. '{0}' is not assignable from '{1}' - error generating code for serialization.. + /// + internal static string IsNotAssignableFrom { + get { + return ResourceManager.GetString("IsNotAssignableFrom", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IsReferenceGetOnlyCollectionsNotSupported: {0}, {1}. + /// + internal static string IsReferenceGetOnlyCollectionsNotSupported { + get { + return ResourceManager.GetString("IsReferenceGetOnlyCollectionsNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}.{1}' has the IsRequired setting of '{2}. However, '{0}' has the IsReference setting of '{2}', because either it is set explicitly, or it is derived from a base class. Set IsRequired on '{0}.{1}' to false, or disable IsReference on '{0}'.. + /// + internal static string IsRequiredDataMemberOnIsReferenceDataContractType { + get { + return ResourceManager.GetString("IsRequiredDataMemberOnIsReferenceDataContractType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is an invalid value for IsValueType annotation. {1}. + /// + internal static string IsValueTypeFormattedIncorrectly { + get { + return ResourceManager.GetString("IsValueTypeFormattedIncorrectly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be IXmlSerializable and have CollectionDataContractAttribute attribute.. + /// + internal static string IXmlSerializableCannotHaveCollectionDataContract { + get { + return ResourceManager.GetString("IXmlSerializableCannotHaveCollectionDataContract", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be IXmlSerializable and have DataContractAttribute attribute.. + /// + internal static string IXmlSerializableCannotHaveDataContract { + get { + return ResourceManager.GetString("IXmlSerializableCannotHaveDataContract", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This method cannot be called from IXmlSerializable implementations.. + /// + internal static string IXmlSerializableIllegalOperation { + get { + return ResourceManager.GetString("IXmlSerializableIllegalOperation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IXmlSerializable.WriteXml method of type '{0}' did not close all open tags. Verify that the IXmlSerializable implementation is correct.. + /// + internal static string IXmlSerializableMissingEndElements { + get { + return ResourceManager.GetString("IXmlSerializableMissingEndElements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IXmlSerializable Type '{0}' must have default constructor.. + /// + internal static string IXmlSerializableMustHaveDefaultConstructor { + get { + return ResourceManager.GetString("IXmlSerializableMustHaveDefaultConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to IXmlSerializable.WriteXml method of type '{0}' attempted to close too many tags. Verify that the IXmlSerializable implementation is correct.. + /// + internal static string IXmlSerializableWritePastSubTree { + get { + return ResourceManager.GetString("IXmlSerializableWritePastSubTree", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot write attribute with local name '{0}' multiple times.. + /// + internal static string JsonAttributeAlreadyWritten { + get { + return ResourceManager.GetString("JsonAttributeAlreadyWritten", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WriteStartElement must be called at least once before WriteStartAttribute may be called.. + /// + internal static string JsonAttributeMustHaveElement { + get { + return ResourceManager.GetString("JsonAttributeMustHaveElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot write a CLR value that maps to number, array, object, true, false or null in JSON after a string value has been written.. + /// + internal static string JsonCannotWriteStandaloneTextAfterQuotedText { + get { + return ResourceManager.GetString("JsonCannotWriteStandaloneTextAfterQuotedText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attempted to write text after writing attribute type='{0}'. Text may be written only after the attributes type='number', type='boolean', or type='string'.. + /// + internal static string JsonCannotWriteTextAfterNonTextAttribute { + get { + return ResourceManager.GetString("JsonCannotWriteTextAfterNonTextAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DateTime values that are greater than DateTime.MaxValue or smaller than DateTime.MinValue when converted to UTC cannot be serialized to JSON.. + /// + internal static string JsonDateTimeOutOfRange { + get { + return ResourceManager.GetString("JsonDateTimeOutOfRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the data member '{1}' was found more than once in the input.. + /// + internal static string JsonDuplicateMemberInInput { + get { + return ResourceManager.GetString("JsonDuplicateMemberInInput", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' is not serializable with DataContractJsonSerializer because the data member '{1}' is duplicated in its type hierarchy.. + /// + internal static string JsonDuplicateMemberNames { + get { + return ResourceManager.GetString("JsonDuplicateMemberNames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encoding not supported in JSON. UTF-8, Unicode, and BigEndianUnicode are the only supported encodings.. + /// + internal static string JsonEncodingNotSupported { + get { + return ResourceManager.GetString("JsonEncodingNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered unexpected character '{0}'.. + /// + internal static string JsonEncounteredUnexpectedCharacter { + get { + return ResourceManager.GetString("JsonEncounteredUnexpectedCharacter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No corresponding start element is open.. + /// + internal static string JsonEndElementNoOpenNodes { + get { + return ResourceManager.GetString("JsonEndElementNoOpenNodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The expected encoding '{0}' does not match the actual encoding '{1}'.. + /// + internal static string JsonExpectedEncoding { + get { + return ResourceManager.GetString("JsonExpectedEncoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid byte encoding.. + /// + internal static string JsonInvalidBytes { + get { + return ResourceManager.GetString("JsonInvalidBytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attempted to write an attribute '{0}'='{1}' after writing the attribute with local name '{2}'. The attribute with local name '{2}' is only valid with an attribute '{0}'='{3}'.. + /// + internal static string JsonInvalidDataTypeSpecifiedForServerType { + get { + return ResourceManager.GetString("JsonInvalidDataTypeSpecifiedForServerType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DateTime content '{0}' does not start with '{1}' and end with '{2}' as required for JSON.. + /// + internal static string JsonInvalidDateTimeString { + get { + return ResourceManager.GetString("JsonInvalidDateTimeString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Characters with hexadecimal values 0xFFFE and 0xFFFF are not valid.. + /// + internal static string JsonInvalidFFFE { + get { + return ResourceManager.GetString("JsonInvalidFFFE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered unexpected element local name '{0}' for item in collection. '{1}' is the only valid local name for elements in a collection.. + /// + internal static string JsonInvalidItemNameForArrayElement { + get { + return ResourceManager.GetString("JsonInvalidItemNameForArrayElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The empty string is not a valid local name in JSON.. + /// + internal static string JsonInvalidLocalNameEmpty { + get { + return ResourceManager.GetString("JsonInvalidLocalNameEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot write content while an attribute is being written.. + /// + internal static string JsonInvalidMethodBetweenStartEndAttribute { + get { + return ResourceManager.GetString("JsonInvalidMethodBetweenStartEndAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered invalid root element name '{0}'. '{1}' is the only allowed root element name.. + /// + internal static string JsonInvalidRootElementName { + get { + return ResourceManager.GetString("JsonInvalidRootElementName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WriteStartElement can be called at only the start of a document or immediately after calling WriteEndElement.. + /// + internal static string JsonInvalidStartElementCall { + get { + return ResourceManager.GetString("JsonInvalidStartElementCall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' cannot be called while WriteState is '{1}'.. + /// + internal static string JsonInvalidWriteState { + get { + return ResourceManager.GetString("JsonInvalidWriteState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This XmlDictionaryWriter implementation does not support the '{0}' method.. + /// + internal static string JsonMethodNotSupported { + get { + return ResourceManager.GetString("JsonMethodNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This XmlDictionaryWriter implementation does not support the writing of multiple root elements.. + /// + internal static string JsonMultipleRootElementsNotAllowedOnWriter { + get { + return ResourceManager.GetString("JsonMultipleRootElementsNotAllowedOnWriter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You must write an attribute '{0}'='{1}' after writing the attribute with local name '{2}'.. + /// + internal static string JsonMustSpecifyDataType { + get { + return ResourceManager.GetString("JsonMustSpecifyDataType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to To write attribute values with this XmlDictionaryWriter implementation, you must write either string or char[] values.. + /// + internal static string JsonMustUseWriteStringForWritingAttributeValues { + get { + return ResourceManager.GetString("JsonMustUseWriteStringForWritingAttributeValues", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered unexpected namespace '{0}'. The namespace must be empty.. + /// + internal static string JsonNamespaceMustBeEmpty { + get { + return ResourceManager.GetString("JsonNamespaceMustBeEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nested arrays are not supported.. + /// + internal static string JsonNestedArraysNotSupported { + get { + return ResourceManager.GetString("JsonNestedArraysNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WriteStartElement cannot be called immediately after WriteStartElement without writing the 'type'='array' or 'type='object' attribute.. + /// + internal static string JsonNodeTypeArrayOrObjectNotSpecified { + get { + return ResourceManager.GetString("JsonNodeTypeArrayOrObjectNotSpecified", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There is no open attribute.. + /// + internal static string JsonNoMatchingStartAttribute { + get { + return ResourceManager.GetString("JsonNoMatchingStartAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified offset exceeds the buffer size ({0} bytes).. + /// + internal static string JsonOffsetExceedsBufferSize { + get { + return ResourceManager.GetString("JsonOffsetExceedsBufferSize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the required data member '{1}' was not found.. + /// + internal static string JsonOneRequiredMemberNotFound { + get { + return ResourceManager.GetString("JsonOneRequiredMemberNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected character '{0}'. '{1}' can write only whitespace characters.. + /// + internal static string JsonOnlyWhitespace { + get { + return ResourceManager.GetString("JsonOnlyWhitespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot call {0} while an attribute is being written.. + /// + internal static string JsonOpenAttributeMustBeClosedFirst { + get { + return ResourceManager.GetString("JsonOpenAttributeMustBeClosedFirst", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered unexpected prefix '{0}'. The prefix must be null or empty.. + /// + internal static string JsonPrefixMustBeNullOrEmpty { + get { + return ResourceManager.GetString("JsonPrefixMustBeNullOrEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the required data members '{1}' were not found.. + /// + internal static string JsonRequiredMembersNotFound { + get { + return ResourceManager.GetString("JsonRequiredMembersNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attempted to write an attribute with local name '{0}' after writing the attribute '{1}'='{2}'. An attribute with local name '{0}' may be written only after writing the attribute '{1}'='{3}'.. + /// + internal static string JsonServerTypeSpecifiedForInvalidDataType { + get { + return ResourceManager.GetString("JsonServerTypeSpecifiedForInvalidDataType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified size exceeds the remaining buffer space ('{0}' bytes).. + /// + internal static string JsonSizeExceedsRemainingBufferSpace { + get { + return ResourceManager.GetString("JsonSizeExceedsRemainingBufferSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DataContractJsonSerializer does not support objects of type '{0}'.. + /// + internal static string JsonTypeNotSupportedByDataContractJsonSerializer { + get { + return ResourceManager.GetString("JsonTypeNotSupportedByDataContractJsonSerializer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Encountered unexpected attribute local name '{0}'. 'type' and '__type' are the only allowed local names for attributes. 'type' can be used to influence how data is written; its valid values are 'object', 'string', 'number', 'null', 'boolean', and 'array'. '__type' can be used to provide type hint information to the writer.. + /// + internal static string JsonUnexpectedAttributeLocalName { + get { + return ResourceManager.GetString("JsonUnexpectedAttributeLocalName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The attribute 'type' must have one of the following strings as its values: 'string', 'number', 'array', 'object', 'null', or 'boolean'. Encountered unexpected value '{0}'. + /// + internal static string JsonUnexpectedAttributeValue { + get { + return ResourceManager.GetString("JsonUnexpectedAttributeValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected end of file.. + /// + internal static string JsonUnexpectedEndOfFile { + get { + return ResourceManager.GetString("JsonUnexpectedEndOfFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type '{0}' cannot be serialized to JSON because its IsReference setting is '{1}'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.. + /// + internal static string JsonUnsupportedForIsReference { + get { + return ResourceManager.GetString("JsonUnsupportedForIsReference", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to To write JSON arrays, use XML writer methods to write the attribute type='array' followed by methods like WriteStartElement (with the local name 'item'), WriteAttributeString, and WriteEndElement to write the JSON array items.. + /// + internal static string JsonWriteArrayNotSupported { + get { + return ResourceManager.GetString("JsonWriteArrayNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The writer is closed.. + /// + internal static string JsonWriterClosed { + get { + return ResourceManager.GetString("JsonWriterClosed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML declaration can only be written at the beginning of the document.. + /// + internal static string JsonXmlInvalidDeclaration { + get { + return ResourceManager.GetString("JsonXmlInvalidDeclaration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Processing instructions (other than the XML declaration) are not supported.. + /// + internal static string JsonXmlProcessingInstructionNotSupported { + get { + return ResourceManager.GetString("JsonXmlProcessingInstructionNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The dictionary of type '{0}' cannot be deserialized as a simple dictionary because its key type '{1}' does not have a public static Parse method.. + /// + internal static string KeyTypeCannotBeParsedInSimpleDictionary { + get { + return ResourceManager.GetString("KeyTypeCannotBeParsedInSimpleDictionary", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method name specified by KnownTypeAttribute attribute on type '{0}' cannot be the empty string.. + /// + internal static string KnownTypeAttributeEmptyString { + get { + return ResourceManager.GetString("KnownTypeAttributeEmptyString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method specified by KnownTypeAttribute attribute on type '{0}' returned null.. + /// + internal static string KnownTypeAttributeMethodNull { + get { + return ResourceManager.GetString("KnownTypeAttributeMethodNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KnownTypeAttribute attribute on type '{0}' contains no data.. + /// + internal static string KnownTypeAttributeNoData { + get { + return ResourceManager.GetString("KnownTypeAttributeNoData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}': If a KnownTypeAttribute attribute specifies a method it must be the only KnownTypeAttribute attribute on that type.. + /// + internal static string KnownTypeAttributeOneScheme { + get { + return ResourceManager.GetString("KnownTypeAttributeOneScheme", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KnownTypeAttribute attribute on type '{0}' specifies a method named '{1}' to provide known types. The return type of this method is invalid because it is not assignable to IEnumerable<Type>. Ensure that the method exists and has a valid signature.. + /// + internal static string KnownTypeAttributeReturnType { + get { + return ResourceManager.GetString("KnownTypeAttributeReturnType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KnownTypeAttribute attribute on type '{1}' specifies a method named '{0}' to provide known types. Static method '{0}()' was not found on this type. Ensure that the method exists and is marked as static.. + /// + internal static string KnownTypeAttributeUnknownMethod { + get { + return ResourceManager.GetString("KnownTypeAttributeUnknownMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method specified by KnownTypeAttribute attribute on type '{0}' does not expose valid types.. + /// + internal static string KnownTypeAttributeValidMethodTypes { + get { + return ResourceManager.GetString("KnownTypeAttributeValidMethodTypes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to KnownTypeConfigClosedGenericDeclared: {0}. + /// + internal static string KnownTypeConfigClosedGenericDeclared { + get { + return ResourceManager.GetString("KnownTypeConfigClosedGenericDeclared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The maximum array length ({0}) has been exceeded while reading XML data for array of type '{1}'.. + /// + internal static string MaxArrayLengthExceeded { + get { + return ResourceManager.GetString("MaxArrayLengthExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' does not have a static method '{1}' that takes a parameter of type 'System.Xml.Schema.XmlSchemaSet' as specified by the XmlSchemaProviderAttribute attribute.. + /// + internal static string MissingGetSchemaMethod { + get { + return ResourceManager.GetString("MissingGetSchemaMethod", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Schema type '{0}' returned by CLR type '{1}' is not found in the XmlSchemaSet.. + /// + internal static string MissingSchemaType { + get { + return ResourceManager.GetString("MissingSchemaType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Complex type with mixed content is not supported.. + /// + internal static string MixedContentNotSupported { + get { + return ResourceManager.GetString("MixedContentNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid XML encountered. The same Id value '{0}' is defined more than once. Multiple objects cannot be deserialized using the same Id.. + /// + internal static string MultipleIdDefinition { + get { + return ResourceManager.GetString("MultipleIdDefinition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The root sequence must contain only local elements. Group ref, choice, any and nested sequences are not supported.. + /// + internal static string MustContainOnlyLocalElements { + get { + return ResourceManager.GetString("MustContainOnlyLocalElements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. No conversion is possible to '{0}' - error generating code for serialization.. + /// + internal static string NoConversionPossibleTo { + get { + return ResourceManager.GetString("NoConversionPossibleTo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Collection type '{0}' doesn't have default constructor.. + /// + internal static string NoDefaultConstructorForCollection { + get { + return ResourceManager.GetString("NoDefaultConstructorForCollection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No get method for property '{1}' in type '{0}'.. + /// + internal static string NoGetMethodForProperty { + get { + return ResourceManager.GetString("NoGetMethodForProperty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Type '{0}' must have a parameterless constructor.. + /// + internal static string NonAttributedSerializableTypesMustHaveDefaultConstructor { + get { + return ResourceManager.GetString("NonAttributedSerializableTypesMustHaveDefaultConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}.{1}' is not marked with OptionalFieldAttribute, thus indicating that it must be serialized. However, '{0}' derives from a class marked with DataContractAttribute and an IsReference setting of '{2}'. It is not possible to have required data members on IsReference classes. Either decorate '{0}.{1}' with OptionalFieldAttribute, or disable the IsReference setting on the appropriate parent class.. + /// + internal static string NonOptionalFieldMemberOnIsReferenceSerializableType { + get { + return ResourceManager.GetString("NonOptionalFieldMemberOnIsReferenceSerializableType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No set method for property '{1}' in type '{0}'.. + /// + internal static string NoSetMethodForProperty { + get { + return ResourceManager.GetString("NoSetMethodForProperty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to One of the known types provided to the serializer via '{0}' argument was invalid because it was null. All known types specified must be non-null values.. + /// + internal static string NullKnownType { + get { + return ResourceManager.GetString("NullKnownType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The get-only collection of type '{0}' returned a null value. The input stream contains collection items which cannot be added if the instance is null. Consider initializing the collection either in the constructor of the object or in the getter.. + /// + internal static string NullValueReturnedForGetOnlyCollection { + get { + return ResourceManager.GetString("NullValueReturnedForGetOnlyCollection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. Object table overflow. This could be caused by serializing or deserializing extremely large object graphs.. + /// + internal static string ObjectTableOverflow { + get { + return ResourceManager.GetString("ObjectTableOverflow", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified offset exceeds the buffer size ({0} bytes).. + /// + internal static string OffsetExceedsBufferSize { + get { + return ResourceManager.GetString("OffsetExceedsBufferSize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' does not have DataContractAttribute attribute and therefore cannot support IExtensibleDataObject. . + /// + internal static string OnlyDataContractTypesCanHaveExtensionData { + get { + return ResourceManager.GetString("OnlyDataContractTypesCanHaveExtensionData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid number of parameters to call method '{0}'. Expected '{1}' parameters, but '{2}' were provided.. + /// + internal static string ParameterCountMismatch { + get { + return ResourceManager.GetString("ParameterCountMismatch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to JsonObjectDataContract.ParseJsonNumber shouldn't return a TypeCode that we're not expecting.. + /// + internal static string ParseJsonNumberReturnInvalidNumber { + get { + return ResourceManager.GetString("ParseJsonNumberReturnInvalidNumber", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The collection data contract type '{0}' cannot be deserialized because the method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustCollectionContractAddMethodNotPublic { + get { + return ResourceManager.GetString("PartialTrustCollectionContractAddMethodNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The collection data contract type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustCollectionContractNoPublicConstructor { + get { + return ResourceManager.GetString("PartialTrustCollectionContractNoPublicConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The collection data contract type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustCollectionContractTypeNotPublic { + get { + return ResourceManager.GetString("PartialTrustCollectionContractTypeNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be serialized because the member '{1}' is not public. Making the member public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractFieldGetNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractFieldGetNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the member '{1}' is not public. Making the member public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractFieldSetNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractFieldSetNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the OnDeserialized method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractOnDeserializedNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractOnDeserializedNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the OnDeserializing method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractOnDeserializingNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractOnDeserializingNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be serialized because the OnSerialized method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractOnSerializedNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractOnSerializedNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be serialized because the OnSerializing method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractOnSerializingNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractOnSerializingNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be serialized because the property '{1}' does not have a public getter. Adding a public getter will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractPropertyGetNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractPropertyGetNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' cannot be deserialized because the property '{1}' does not have a public setter. Adding a public setter will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractPropertySetNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractPropertySetNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data contract type '{0}' is not serializable because it is not public. Making the type public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustDataContractTypeNotPublic { + get { + return ResourceManager.GetString("PartialTrustDataContractTypeNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to PartialTrustISerializableNoPublicConstructor: {0}. + /// + internal static string PartialTrustISerializableNoPublicConstructor { + get { + return ResourceManager.GetString("PartialTrustISerializableNoPublicConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The IXmlSerializable type '{0}' is not serializable in partial trust because it is not public. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustIXmlSerializableTypeNotPublic { + get { + return ResourceManager.GetString("PartialTrustIXmlSerializableTypeNotPublic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The IXmlSerializable type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustIXmlSerialzableNoPublicConstructor { + get { + return ResourceManager.GetString("PartialTrustIXmlSerialzableNoPublicConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications.. + /// + internal static string PartialTrustNonAttributedSerializableTypeNoPublicConstructor { + get { + return ResourceManager.GetString("PartialTrustNonAttributedSerializableTypeNoPublicConstructor", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The canonicalization process is not supported on this platform.. + /// + internal static string PlatformNotSupported_Canonicalization { + get { + return ResourceManager.GetString("PlatformNotSupported_Canonicalization", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The implementation of the function requires System.Runtime.Serialization.IDataContractSurrogate which is not supported on this platform.. + /// + internal static string PlatformNotSupported_IDataContractSurrogate { + get { + return ResourceManager.GetString("PlatformNotSupported_IDataContractSurrogate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The Message Transmission Optimization Mechanism (MTOM) message encoding is not supported on this platform.. + /// + internal static string PlatformNotSupported_MtomEncoding { + get { + return ResourceManager.GetString("PlatformNotSupported_MtomEncoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System.Runtime.Serialization.NetDataContractSerializer is not supported on this platform.. + /// + internal static string PlatformNotSupported_NetDataContractSerializer { + get { + return ResourceManager.GetString("PlatformNotSupported_NetDataContractSerializer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The implementation of the function requires System.Runtime.Serialization.SchemaImporter which is not supported on this platform.. + /// + internal static string PlatformNotSupported_SchemaImporter { + get { + return ResourceManager.GetString("PlatformNotSupported_SchemaImporter", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot find a path to the member when generating the XPath query.. + /// + internal static string QueryGeneratorPathToMemberNotFound { + get { + return ResourceManager.GetString("QueryGeneratorPathToMemberNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot copy XmlDictionaryReaderQuotas. Target is readonly.. + /// + internal static string QuotaCopyReadOnly { + get { + return ResourceManager.GetString("QuotaCopyReadOnly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The '{0}' quota is readonly.. + /// + internal static string QuotaIsReadOnly { + get { + return ResourceManager.GetString("QuotaIsReadOnly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quota must be a positive value.. + /// + internal static string QuotaMustBePositive { + get { + return ResourceManager.GetString("QuotaMustBePositive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ReadOnlyClassDeserialization: {0}. + /// + internal static string ReadOnlyClassDeserialization { + get { + return ResourceManager.GetString("ReadOnlyClassDeserialization", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ReadOnlyCollectionDeserialization: {0}. + /// + internal static string ReadOnlyCollectionDeserialization { + get { + return ResourceManager.GetString("ReadOnlyCollectionDeserialization", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' is a recursive collection data contract which is not supported. Consider modifying the definition of collection '{0}' to remove references to itself.. + /// + internal static string RecursiveCollectionType { + get { + return ResourceManager.GetString("RecursiveCollectionType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Redefine is not supported.. + /// + internal static string RedefineNotSupported { + get { + return ResourceManager.GetString("RedefineNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ReferencedCollectionTypesCannotContainNull. + /// + internal static string ReferencedCollectionTypesCannotContainNull { + get { + return ResourceManager.GetString("ReferencedCollectionTypesCannotContainNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (matching). + /// + internal static string ReferencedTypeMatchingMessage { + get { + return ResourceManager.GetString("ReferencedTypeMatchingMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to (not matching). + /// + internal static string ReferencedTypeNotMatchingMessage { + get { + return ResourceManager.GetString("ReferencedTypeNotMatchingMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ReferencedTypesCannotContainNull. + /// + internal static string ReferencedTypesCannotContainNull { + get { + return ResourceManager.GetString("ReferencedTypesCannotContainNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member {0} in type {1} cannot be serialized. This exception is usually caused by trying to use a null value where a null value is not allowed. The '{0}' member is set to its default value (usually null or zero). The member's EmitDefault setting is 'false', indicating that the member should not be serialized. However, the member's IsRequired setting is 'true', indicating that it must be serialized. This conflict cannot be resolved. Consider setting '{0}' to a non-default value. Alternatively, you can change [rest of string was truncated]";. + /// + internal static string RequiredMemberMustBeEmitted { + get { + return ResourceManager.GetString("RequiredMemberMustBeEmitted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only classes can be generated as ISerializable.. + /// + internal static string RequiresClassDataContractToSetIsISerializable { + get { + return ResourceManager.GetString("RequiresClassDataContractToSetIsISerializable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An object of type '{0}' which derives from DataContractResolver returned false from its TryResolveType method when attempting to resolve the name for an object of type '{1}', indicating that the resolution failed. Change the TryResolveType implementation to return true.. + /// + internal static string ResolveTypeReturnedFalse { + get { + return ResourceManager.GetString("ResolveTypeReturnedFalse", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An object of type '{0}' which derives from DataContractResolver returned a null typeName or typeNamespace but not both from its TryResolveType method when attempting to resolve the name for an object of type '{1}'. Change the TryResolveType implementation to return non-null values, or to return null values for both typeName and typeNamespace in order to serialize as the declared type.. + /// + internal static string ResolveTypeReturnedNull { + get { + return ResourceManager.GetString("ResolveTypeReturnedNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The root particle must be a sequence.. + /// + internal static string RootParticleMustBeSequence { + get { + return ResourceManager.GetString("RootParticleMustBeSequence", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'maxOccurs' on the root sequence must be 1.. + /// + internal static string RootSequenceMaxOccursMustBe { + get { + return ResourceManager.GetString("RootSequenceMaxOccursMustBe", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'minOccurs' on the root sequence must be 1.. + /// + internal static string RootSequenceMustBeRequired { + get { + return ResourceManager.GetString("RootSequenceMustBeRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be serialized, serialization code for the type is missing. Consult the SDK documentation for adding it as a root serialization type.. + /// + internal static string SerializationCodeIsMissingForType { + get { + return ResourceManager.GetString("SerializationCodeIsMissingForType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The constructor with parameters (SerializationInfo, StreamingContext) is not found in ISerializable type '{0}'.. + /// + internal static string SerializationInfo_ConstructorNotFound { + get { + return ResourceManager.GetString("SerializationInfo_ConstructorNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Complex types with simple content extension are not supported.. + /// + internal static string SimpleContentNotSupported { + get { + return ResourceManager.GetString("SimpleContentNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Simple type restriction must specify a base type.. + /// + internal static string SimpleTypeRestrictionDoesNotSpecifyBase { + get { + return ResourceManager.GetString("SimpleTypeRestrictionDoesNotSpecifyBase", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Simple types with <union> content are not supported.. + /// + internal static string SimpleTypeUnionNotSupported { + get { + return ResourceManager.GetString("SimpleTypeUnionNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified size exceeds the remaining buffer space ({0} bytes).. + /// + internal static string SizeExceedsRemainingBufferSpace { + get { + return ResourceManager.GetString("SizeExceedsRemainingBufferSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid type specified. Type with name '{0}' not found in schema with namespace '{1}'.. + /// + internal static string SpecifiedTypeNotFoundInSchema { + get { + return ResourceManager.GetString("SpecifiedTypeNotFoundInSchema", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Substitution group on element '{0}' is not supported.. + /// + internal static string SubstitutionGroupOnElementNotSupported { + get { + return ResourceManager.GetString("SubstitutionGroupOnElementNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Multi-dimensional arrays are not supported.. + /// + internal static string SupportForMultidimensionalArraysNotPresent { + get { + return ResourceManager.GetString("SupportForMultidimensionalArraysNotPresent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SurrogatesWithGetOnlyCollectionsNotSupported: {0}, {1}, {2}. + /// + internal static string SurrogatesWithGetOnlyCollectionsNotSupported { + get { + return ResourceManager.GetString("SurrogatesWithGetOnlyCollectionsNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using surrogates with get-only collection properties is not supported. Consider removing the surrogate associated with '{0}'.. + /// + internal static string SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser { + get { + return ResourceManager.GetString("SurrogatesWithGetOnlyCollectionsNotSupportedSerDeser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' has more than one CollectionDataContractAttribute attribute.. + /// + internal static string TooManyCollectionContracts { + get { + return ResourceManager.GetString("TooManyCollectionContracts", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' has more than one DataContractAttribute attribute.. + /// + internal static string TooManyDataContracts { + get { + return ResourceManager.GetString("TooManyDataContracts", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member '{0}.{1}' has more than one DataMemberAttribute attribute.. + /// + internal static string TooManyDataMembers { + get { + return ResourceManager.GetString("TooManyDataMembers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member '{0}.{1}' has more than one EnumMemberAttribute attribute.. + /// + internal static string TooManyEnumMembers { + get { + return ResourceManager.GetString("TooManyEnumMembers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member '{0}.{1}' has more than one IgnoreDataMemberAttribute attribute.. + /// + internal static string TooManyIgnoreDataMemberAttributes { + get { + return ResourceManager.GetString("TooManyIgnoreDataMemberAttributes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The global element found in the schema with same name references a different type '{0}' in namespace '{1}'. Data contract types must have the same name as their root element name. Consider removing the global element or changing its type.. + /// + internal static string TopLevelElementRepresentsDifferentType { + get { + return ResourceManager.GetString("TopLevelElementRepresentsDifferentType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TypeCannotBeForwardedFrom: {0}, {1}, {2}. + /// + internal static string TypeCannotBeForwardedFrom { + get { + return ResourceManager.GetString("TypeCannotBeForwardedFrom", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' in namespace '{1}' cannot be imported. {2}. + /// + internal static string TypeCannotBeImported { + get { + return ResourceManager.GetString("TypeCannotBeImported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer.. + /// + internal static string TypeCannotBeImportedHowToFix { + get { + return ResourceManager.GetString("TypeCannotBeImportedHowToFix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TypeMustBeConcrete: {0}. + /// + internal static string TypeMustBeConcrete { + get { + return ResourceManager.GetString("TypeMustBeConcrete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.. + /// + internal static string TypeNotSerializable { + get { + return ResourceManager.GetString("TypeNotSerializable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attributes must be optional and from namespace '{0}'.. + /// + internal static string TypeShouldNotContainAttributes { + get { + return ResourceManager.GetString("TypeShouldNotContainAttributes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An internal error has occurred. Unexpected contract type '{0}' for type '{1}' encountered.. + /// + internal static string UnexpectedContractType { + get { + return ResourceManager.GetString("UnexpectedContractType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' '{1}' from namespace '{2}' is not expected. Expecting element '{3}'.. + /// + internal static string UnexpectedElementExpectingElements { + get { + return ResourceManager.GetString("UnexpectedElementExpectingElements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected end of file.. + /// + internal static string UnexpectedEndOfFile { + get { + return ResourceManager.GetString("UnexpectedEndOfFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Internal Error: Unrecognized constant type {0}.. + /// + internal static string UnknownConstantType { + get { + return ResourceManager.GetString("UnknownConstantType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' is not a valid XML type.. + /// + internal static string UnknownXmlType { + get { + return ResourceManager.GetString("UnknownXmlType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value of this argument must fall within the range {0} to {1}.. + /// + internal static string ValueMustBeInRange { + get { + return ResourceManager.GetString("ValueMustBeInRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value of this argument must be non-negative.. + /// + internal static string ValueMustBeNonNegative { + get { + return ResourceManager.GetString("ValueMustBeNonNegative", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ValueType '{0}' cannot be null.. + /// + internal static string ValueTypeCannotBeNull { + get { + return ResourceManager.GetString("ValueTypeCannotBeNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data contract '{0}' from namespace '{1}' is a value type and cannot have base contract '{2}' from namespace '{3}'.. + /// + internal static string ValueTypeCannotHaveBaseType { + get { + return ResourceManager.GetString("ValueTypeCannotHaveBaseType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ValueType '{0}' cannot have id.. + /// + internal static string ValueTypeCannotHaveId { + get { + return ResourceManager.GetString("ValueTypeCannotHaveId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value type '{0}' cannot have the IsReference setting of '{1}'. Either change the setting to '{2}', or remove it completely. . + /// + internal static string ValueTypeCannotHaveIsReference { + get { + return ResourceManager.GetString("ValueTypeCannotHaveIsReference", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ValueType '{0}' cannot have ref to another object.. + /// + internal static string ValueTypeCannotHaveRef { + get { + return ResourceManager.GetString("ValueTypeCannotHaveRef", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array too small.. + /// + internal static string XmlArrayTooSmall { + get { + return ResourceManager.GetString("XmlArrayTooSmall", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array too small. Length of available data must be at least {0}.. + /// + internal static string XmlArrayTooSmallInput { + get { + return ResourceManager.GetString("XmlArrayTooSmallInput", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Array too small. Must be able to hold at least {0}.. + /// + internal static string XmlArrayTooSmallOutput { + get { + return ResourceManager.GetString("XmlArrayTooSmallOutput", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An asynchronous operation is already in progress.. + /// + internal static string XmlAsyncIsRunningException { + get { + return ResourceManager.GetString("XmlAsyncIsRunningException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unrecognized Byte Order Mark.. + /// + internal static string XmlBadBOM { + get { + return ResourceManager.GetString("XmlBadBOM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Base64 encoded data expected. Found {0}.. + /// + internal static string XmlBase64DataExpected { + get { + return ResourceManager.GetString("XmlBase64DataExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Canonicalization not started.. + /// + internal static string XmlCanonicalizationNotStarted { + get { + return ResourceManager.GetString("XmlCanonicalizationNotStarted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Canonicalization already started.. + /// + internal static string XmlCanonicalizationStarted { + get { + return ResourceManager.GetString("XmlCanonicalizationStarted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CData elements not valid at top level of an XML document.. + /// + internal static string XmlCDATAInvalidAtTopLevel { + get { + return ResourceManager.GetString("XmlCDATAInvalidAtTopLevel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ']]>' not valid in text node content.. + /// + internal static string XmlCloseCData { + get { + return ResourceManager.GetString("XmlCloseCData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value '{0}' cannot be represented with the type '{1}'.. + /// + internal static string XmlConversionOverflow { + get { + return ResourceManager.GetString("XmlConversionOverflow", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An XML declaration with an encoding is required for all non-UTF8 documents.. + /// + internal static string XmlDeclarationRequired { + get { + return ResourceManager.GetString("XmlDeclarationRequired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An XML declaration is required for all non-UTF8 documents.. + /// + internal static string XmlDeclMissing { + get { + return ResourceManager.GetString("XmlDeclMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version not found in XML declaration.. + /// + internal static string XmlDeclMissingVersion { + get { + return ResourceManager.GetString("XmlDeclMissingVersion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No characters can appear before the XML declaration.. + /// + internal static string XmlDeclNotFirst { + get { + return ResourceManager.GetString("XmlDeclNotFirst", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XmlDictionaryString IDs must be in the range from {0} to {1}.. + /// + internal static string XmlDictionaryStringIDRange { + get { + return ResourceManager.GetString("XmlDictionaryStringIDRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XmlDictionaryString ID {0} not defined in the XmlBinaryReaderSession.. + /// + internal static string XmlDictionaryStringIDUndefinedSession { + get { + return ResourceManager.GetString("XmlDictionaryStringIDUndefinedSession", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XmlDictionaryString ID {0} not defined in the static dictionary.. + /// + internal static string XmlDictionaryStringIDUndefinedStatic { + get { + return ResourceManager.GetString("XmlDictionaryStringIDUndefinedStatic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Duplicate attribute found. Both '{0}' and '{1}' are from the namespace '{2}'.. + /// + internal static string XmlDuplicateAttribute { + get { + return ResourceManager.GetString("XmlDuplicateAttribute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only Element nodes have attributes.. + /// + internal static string XmlElementAttributes { + get { + return ResourceManager.GetString("XmlElementAttributes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The empty namespace requires a null or empty prefix.. + /// + internal static string XmlEmptyNamespaceRequiresNullPrefix { + get { + return ResourceManager.GetString("XmlEmptyNamespaceRequiresNullPrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The encoding in the declaration '{0}' does not match the encoding of the document '{1}'.. + /// + internal static string XmlEncodingMismatch { + get { + return ResourceManager.GetString("XmlEncodingMismatch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML encoding not supported.. + /// + internal static string XmlEncodingNotSupported { + get { + return ResourceManager.GetString("XmlEncodingNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to End element '{0}' from namespace '{1}' expected. Found {2}.. + /// + internal static string XmlEndElementExpected { + get { + return ResourceManager.GetString("XmlEndElementExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No corresponding start element is open.. + /// + internal static string XmlEndElementNoOpenNodes { + get { + return ResourceManager.GetString("XmlEndElementNoOpenNodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The expected encoding '{0}' does not match the actual encoding '{1}'.. + /// + internal static string XmlExpectedEncoding { + get { + return ResourceManager.GetString("XmlExpectedEncoding", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Element {0} from namespace {1} cannot have child contents to be deserialized as an object. Please use XElement to deserialize this pattern of XML.. + /// + internal static string XmlForObjectCannotHaveContent { + get { + return ResourceManager.GetString("XmlForObjectCannotHaveContent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to cdata '{0}'. + /// + internal static string XmlFoundCData { + get { + return ResourceManager.GetString("XmlFoundCData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to comment '{0}'. + /// + internal static string XmlFoundComment { + get { + return ResourceManager.GetString("XmlFoundComment", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to element '{0}' from namespace '{1}'. + /// + internal static string XmlFoundElement { + get { + return ResourceManager.GetString("XmlFoundElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to end element '{0}' from namespace '{1}'. + /// + internal static string XmlFoundEndElement { + get { + return ResourceManager.GetString("XmlFoundEndElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to end of file. + /// + internal static string XmlFoundEndOfFile { + get { + return ResourceManager.GetString("XmlFoundEndOfFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to node {0}. + /// + internal static string XmlFoundNodeType { + get { + return ResourceManager.GetString("XmlFoundNodeType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to text '{0}'. + /// + internal static string XmlFoundText { + get { + return ResourceManager.GetString("XmlFoundText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-empty start element expected. Found {0}.. + /// + internal static string XmlFullStartElementExpected { + get { + return ResourceManager.GetString("XmlFullStartElementExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-empty start element '{0}' from namespace '{1}' expected. Found {2}.. + /// + internal static string XmlFullStartElementLocalNameNsExpected { + get { + return ResourceManager.GetString("XmlFullStartElementLocalNameNsExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-empty start element '{0}' expected. Found {1}.. + /// + internal static string XmlFullStartElementNameExpected { + get { + return ResourceManager.GetString("XmlFullStartElementNameExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ID already defined.. + /// + internal static string XmlIDDefined { + get { + return ResourceManager.GetString("XmlIDDefined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Text cannot be written outside the root element.. + /// + internal static string XmlIllegalOutsideRoot { + get { + return ResourceManager.GetString("XmlIllegalOutsideRoot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Base64 sequence length ({0}) not valid. Must be a multiple of 4.. + /// + internal static string XmlInvalidBase64Length { + get { + return ResourceManager.GetString("XmlInvalidBase64Length", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The characters '{0}' at offset {1} are not a valid Base64 sequence.. + /// + internal static string XmlInvalidBase64Sequence { + get { + return ResourceManager.GetString("XmlInvalidBase64Sequence", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to BinHex sequence length ({0}) not valid. Must be a multiple of 2.. + /// + internal static string XmlInvalidBinHexLength { + get { + return ResourceManager.GetString("XmlInvalidBinHexLength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The characters '{0}' at offset {1} are not a valid BinHex sequence.. + /// + internal static string XmlInvalidBinHexSequence { + get { + return ResourceManager.GetString("XmlInvalidBinHexSequence", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid byte encoding.. + /// + internal static string XmlInvalidBytes { + get { + return ResourceManager.GetString("XmlInvalidBytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Character reference not valid.. + /// + internal static string XmlInvalidCharRef { + get { + return ResourceManager.GetString("XmlInvalidCharRef", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML comments cannot contain '--' or end with '-'.. + /// + internal static string XmlInvalidCommentChars { + get { + return ResourceManager.GetString("XmlInvalidCommentChars", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value '{0}' cannot be parsed as the type '{1}'.. + /// + internal static string XmlInvalidConversion { + get { + return ResourceManager.GetString("XmlInvalidConversion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value cannot be parsed as the type '{0}'.. + /// + internal static string XmlInvalidConversionWithoutValue { + get { + return ResourceManager.GetString("XmlInvalidConversionWithoutValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML declaration can only be written at the beginning of the document.. + /// + internal static string XmlInvalidDeclaration { + get { + return ResourceManager.GetString("XmlInvalidDeclaration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot call '{0}' while Depth is '{1}'.. + /// + internal static string XmlInvalidDepth { + get { + return ResourceManager.GetString("XmlInvalidDepth", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML encoding must be 'UTF-8'.. + /// + internal static string XmlInvalidEncoding_UTF8 { + get { + return ResourceManager.GetString("XmlInvalidEncoding_UTF8", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Characters with hexadecimal values 0xFFFE and 0xFFFF are not valid.. + /// + internal static string XmlInvalidFFFE { + get { + return ResourceManager.GetString("XmlInvalidFFFE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The input source is not correctly formatted.. + /// + internal static string XmlInvalidFormat { + get { + return ResourceManager.GetString("XmlInvalidFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to High surrogate char '0x{0}' not valid. High surrogate chars range from 0xD800 to 0xDBFF.. + /// + internal static string XmlInvalidHighSurrogate { + get { + return ResourceManager.GetString("XmlInvalidHighSurrogate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ID must be >. + /// + internal static string XmlInvalidID { + get { + return ResourceManager.GetString("XmlInvalidID", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Low surrogate char '0x{0}' not valid. Low surrogate chars range from 0xDC00 to 0xDFFF.. + /// + internal static string XmlInvalidLowSurrogate { + get { + return ResourceManager.GetString("XmlInvalidLowSurrogate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The reader cannot be advanced.. + /// + internal static string XmlInvalidOperation { + get { + return ResourceManager.GetString("XmlInvalidOperation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A prefix cannot be defined while WriteState is '{0}'.. + /// + internal static string XmlInvalidPrefixState { + get { + return ResourceManager.GetString("XmlInvalidPrefixState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expected XML qualified name. Found '{0}'.. + /// + internal static string XmlInvalidQualifiedName { + get { + return ResourceManager.GetString("XmlInvalidQualifiedName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The data at the root level is invalid.. + /// + internal static string XmlInvalidRootData { + get { + return ResourceManager.GetString("XmlInvalidRootData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 'standalone' value in declaration must be 'yes' or 'no'.. + /// + internal static string XmlInvalidStandalone { + get { + return ResourceManager.GetString("XmlInvalidStandalone", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream returned by IStreamProvider cannot be null.. + /// + internal static string XmlInvalidStream { + get { + return ResourceManager.GetString("XmlInvalidStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Surrogate char '0x{0}' not valid. Surrogate chars range from 0x10000 to 0x10FFFF.. + /// + internal static string XmlInvalidSurrogate { + get { + return ResourceManager.GetString("XmlInvalidSurrogate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to UniqueId cannot be zero length.. + /// + internal static string XmlInvalidUniqueId { + get { + return ResourceManager.GetString("XmlInvalidUniqueId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' contains invalid UTF8 bytes.. + /// + internal static string XmlInvalidUTF8Bytes { + get { + return ResourceManager.GetString("XmlInvalidUTF8Bytes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XML version must be '1.0'.. + /// + internal static string XmlInvalidVersion { + get { + return ResourceManager.GetString("XmlInvalidVersion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' cannot be called while WriteState is '{1}'.. + /// + internal static string XmlInvalidWriteState { + get { + return ResourceManager.GetString("XmlInvalidWriteState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The byte 0x{0} is not valid at this location.. + /// + internal static string XmlInvalidXmlByte { + get { + return ResourceManager.GetString("XmlInvalidXmlByte", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is not a valid xml:space value. Valid values are 'default' and 'preserve'.. + /// + internal static string XmlInvalidXmlSpace { + get { + return ResourceManager.GetString("XmlInvalidXmlSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The specified key already exists in the dictionary.. + /// + internal static string XmlKeyAlreadyExists { + get { + return ResourceManager.GetString("XmlKeyAlreadyExists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Line {0}, position {1}.. + /// + internal static string XmlLineInfo { + get { + return ResourceManager.GetString("XmlLineInfo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Malformed XML declaration.. + /// + internal static string XmlMalformedDecl { + get { + return ResourceManager.GetString("XmlMalformedDecl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The maximum array length quota ({0}) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.. + /// + internal static string XmlMaxArrayLengthExceeded { + get { + return ResourceManager.GetString("XmlMaxArrayLengthExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to XmlMaxArrayLengthOrMaxItemsQuotaExceeded: {0}. + /// + internal static string XmlMaxArrayLengthOrMaxItemsQuotaExceeded { + get { + return ResourceManager.GetString("XmlMaxArrayLengthOrMaxItemsQuotaExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'maximum bytes per Read operation' quota ({0}) has been exceeded while reading XML data. Long element start tags (consisting of the element name, attribute names and attribute values) may trigger this quota. This quota may be increased by changing the MaxBytesPerRead property on the XmlDictionaryReaderQuotas object used when creating the XML reader.. + /// + internal static string XmlMaxBytesPerReadExceeded { + get { + return ResourceManager.GetString("XmlMaxBytesPerReadExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The maximum read depth ({0}) has been exceeded because XML data being read has more levels of nesting than is allowed by the quota. This quota may be increased by changing the MaxDepth property on the XmlDictionaryReaderQuotas object used when creating the XML reader.. + /// + internal static string XmlMaxDepthExceeded { + get { + return ResourceManager.GetString("XmlMaxDepthExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The maximum string content length quota ({0}) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.. + /// + internal static string XmlMaxStringContentLengthExceeded { + get { + return ResourceManager.GetString("XmlMaxStringContentLengthExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This XmlWriter implementation does not support the '{0}' method.. + /// + internal static string XmlMethodNotSupported { + get { + return ResourceManager.GetString("XmlMethodNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The surrogate pair is invalid. Missing a low surrogate character.. + /// + internal static string XmlMissingLowSurrogate { + get { + return ResourceManager.GetString("XmlMissingLowSurrogate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are multiple root elements.. + /// + internal static string XmlMultipleRootElements { + get { + return ResourceManager.GetString("XmlMultipleRootElements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The namespace '{0}' is not defined.. + /// + internal static string XmlNamespaceNotFound { + get { + return ResourceManager.GetString("XmlNamespaceNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nested arrays are not supported.. + /// + internal static string XmlNestedArraysNotSupported { + get { + return ResourceManager.GetString("XmlNestedArraysNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The document does not have a root element.. + /// + internal static string XmlNoRootElement { + get { + return ResourceManager.GetString("XmlNoRootElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is an XML type and cannot be serialized when assigned to an interface type that does not implement IXmlSerializable ('{1}'.). + /// + internal static string XmlObjectAssignedToIncompatibleInterface { + get { + return ResourceManager.GetString("XmlObjectAssignedToIncompatibleInterface", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only one root element is permitted per document.. + /// + internal static string XmlOnlyOneRoot { + get { + return ResourceManager.GetString("XmlOnlyOneRoot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only a single typed value may be written inside an attribute or content.. + /// + internal static string XmlOnlySingleValue { + get { + return ResourceManager.GetString("XmlOnlySingleValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only whitespace characters can be written with this method.. + /// + internal static string XmlOnlyWhitespace { + get { + return ResourceManager.GetString("XmlOnlyWhitespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The prefix '{0}' is bound to the namespace '{1}' and cannot be changed to '{2}'.. + /// + internal static string XmlPrefixBoundToNamespace { + get { + return ResourceManager.GetString("XmlPrefixBoundToNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Processing instructions (other than the XML declaration) and DTDs are not supported.. + /// + internal static string XmlProcessingInstructionNotSupported { + get { + return ResourceManager.GetString("XmlProcessingInstructionNotSupported", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Prefixes beginning with 'xml' (regardless of casing) are reserved for use by XML.. + /// + internal static string XmlReservedPrefix { + get { + return ResourceManager.GetString("XmlReservedPrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whitespace must appear between attributes.. + /// + internal static string XmlSpaceBetweenAttributes { + get { + return ResourceManager.GetString("XmlSpaceBetweenAttributes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The namespace '{1}' can only be bound to the prefix '{0}'.. + /// + internal static string XmlSpecificBindingNamespace { + get { + return ResourceManager.GetString("XmlSpecificBindingNamespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The prefix '{0}' can only be bound to the namespace '{1}'.. + /// + internal static string XmlSpecificBindingPrefix { + get { + return ResourceManager.GetString("XmlSpecificBindingPrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start element expected. Found {0}.. + /// + internal static string XmlStartElementExpected { + get { + return ResourceManager.GetString("XmlStartElementExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start element '{0}' from namespace '{1}' expected. Found {2}.. + /// + internal static string XmlStartElementLocalNameNsExpected { + get { + return ResourceManager.GetString("XmlStartElementLocalNameNsExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start element '{0}' expected. Found {1}.. + /// + internal static string XmlStartElementNameExpected { + get { + return ResourceManager.GetString("XmlStartElementNameExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start element '{0}' does not match end element '{1}'.. + /// + internal static string XmlTagMismatch { + get { + return ResourceManager.GetString("XmlTagMismatch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The token '{0}' was expected but found '{1}'.. + /// + internal static string XmlTokenExpected { + get { + return ResourceManager.GetString("XmlTokenExpected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The prefix '{0}' is not defined.. + /// + internal static string XmlUndefinedPrefix { + get { + return ResourceManager.GetString("XmlUndefinedPrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No matching start tag for end element.. + /// + internal static string XmlUnexpectedEndElement { + get { + return ResourceManager.GetString("XmlUnexpectedEndElement", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected end of file. Following elements are not closed: {0}.. + /// + internal static string XmlUnexpectedEndOfFile { + get { + return ResourceManager.GetString("XmlUnexpectedEndOfFile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The XmlWriter is closed.. + /// + internal static string XmlWriterClosed { + get { + return ResourceManager.GetString("XmlWriterClosed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WriteState '{0}' not valid. Caller must write start element before serializing in contentOnly mode.. + /// + internal static string XmlWriterMustBeInElement { + get { + return ResourceManager.GetString("XmlWriterMustBeInElement", resourceCulture); + } + } + } +} diff --git a/Compat.Private.Serialization/Resources/Common/SR.cs b/Compat.Private.Serialization/Resources/Common/SR.cs new file mode 100644 index 0000000..5d63995 --- /dev/null +++ b/Compat.Private.Serialization/Resources/Common/SR.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Resources; +using System.Runtime.CompilerServices; + +namespace Compat +{ + internal partial class SR + { + // This method is used to decide if we need to append the exception message parameters to the message when calling SR.Format. + // by default it returns false. + // Native code generators can replace the value this returns based on user input at the time of native code generation. + // Marked as NoInlining because if this is used in an AoT compiled app that is not compiled into a single file, the user + // could compile each module with a different setting for this. We want to make sure there's a consistent behavior + // that doesn't depend on which native module this method got inlined into. + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool UsingResourceKeys() => false; + + internal static string GetResourceString(string resourceKey, string? defaultString = null) + { + if (UsingResourceKeys()) + { + return defaultString ?? resourceKey; + } + + string? resourceString = null; + try + { + resourceString = ResourceManager.GetString(resourceKey); + } + catch (MissingManifestResourceException) { } + + if (defaultString != null && resourceKey.Equals(resourceString)) + { + return defaultString; + } + + return resourceString!; // only null if missing resources + } + + internal static string Format(string resourceFormat, object? p1) + { + if (UsingResourceKeys()) + { + return string.Join(", ", resourceFormat, p1); + } + + return string.Format(resourceFormat, p1); + } + + internal static string Format(string resourceFormat, object? p1, object? p2) + { + if (UsingResourceKeys()) + { + return string.Join(", ", resourceFormat, p1, p2); + } + + return string.Format(resourceFormat, p1, p2); + } + + internal static string Format(string resourceFormat, object? p1, object? p2, object? p3) + { + if (UsingResourceKeys()) + { + return string.Join(", ", resourceFormat, p1, p2, p3); + } + + return string.Format(resourceFormat, p1, p2, p3); + } + + internal static string Format(string resourceFormat, params object?[]? args) + { + if (args != null) + { + if (UsingResourceKeys()) + { + return resourceFormat + ", " + string.Join(", ", args); + } + + return string.Format(resourceFormat, args); + } + + return resourceFormat; + } + + internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1) + { + if (UsingResourceKeys()) + { + return string.Join(", ", resourceFormat, p1); + } + + return string.Format(provider, resourceFormat, p1); + } + + internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2) + { + if (UsingResourceKeys()) + { + return string.Join(", ", resourceFormat, p1, p2); + } + + return string.Format(provider, resourceFormat, p1, p2); + } + + internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2, object? p3) + { + if (UsingResourceKeys()) + { + return string.Join(", ", resourceFormat, p1, p2, p3); + } + + return string.Format(provider, resourceFormat, p1, p2, p3); + } + + internal static string Format(IFormatProvider? provider, string resourceFormat, params object?[]? args) + { + if (args != null) + { + if (UsingResourceKeys()) + { + return resourceFormat + ", " + string.Join(", ", args); + } + + return string.Format(provider, resourceFormat, args); + } + + return resourceFormat; + } + } +} diff --git a/Compat.Private.Serialization/Resources/SR.resx b/Compat.Private.Serialization/Resources/SR.resx new file mode 100644 index 0000000..efe28d2 --- /dev/null +++ b/Compat.Private.Serialization/Resources/SR.resx @@ -0,0 +1,1431 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Array length '{0}' provided by the get-only collection of type '{1}' is less than the number of array elements found in the input stream. Consider increasing the length of the array. + + + Array length '{0}' provided by Size attribute is not equal to the number of array elements '{1}' from namespace '{2}' found. + + + An internal error has occurred. '{0}[]' is not supported when generating code for serialization. + + + Cannot deserialize since root element references unrecognized object with id '{0}'. + + + Cannot load member type '{0}'. + + + Object graph for type '{0}' contains cycles and cannot be serialized if references are not tracked. Consider using the DataContractAttribute with the IsReference property set to true. + + + An internal error has occurred. Data can only be stored into ArgBuilder or LocalBuilder. Got: {0}. + + + An internal error has occurred. Char is not a valid schema primitive and should be treated as int in DataContract. + + + Serialization Callback '{1}' in type '{0}' must return void. + + + Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'. + + + Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute. + + + Collection type '{0}' does not have a valid Add method. + + + Collection type '{0}' does not have a valid GetEnumerator method. + + + Collection type '{0}' must have a non-null item type. + + + {0} is a built-in type and cannot be a collection. + + + {0} has DataContractAttribute attribute. + + + {0} does not have a valid Add method with parameter of type '{1}'. + + + {0} does not have a default constructor. + + + {0} has multiple definitions of interface '{1}'. + + + {0} does not implement IEnumerable interface. + + + An internal error has occurred. DataContract cache overflow. + + + ContractNamespaceAttribute attribute maps CLR namespace '{2}' to multiple data contract namespaces '{0}' and '{1}'. You can map a CLR namespace to only one data contract namespace. + + + DataContract namespace '{0}' is not a valid URI. + + + DataContract namespace '{0}' cannot be specified since it is reserved. + + + Member '{0}.{1}' has DataMemberAttribute attribute. Use EnumMemberAttribute attribute instead. + + + Element '{2}:{3}' contains data of the '{0}:{1}' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to '{1}' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer. + + + Type '{0}' with data contract name '{1}:{2}' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer. + + + Element '{2}:{3}' contains data from a type that maps to the name '{0}:{1}'. The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name '{1}' and namespace '{0}'. + + + Deserialized object with reference id '{0}' not found in stream. + + + Type '{0}' cannot be added to list of known types since another type '{1}' with the same data contract name '{2}:{3}' is already present. + + + The collection data contract type '{0}' specifies the same value '{1}' for both the KeyName and the ValueName properties. This is not allowed. Consider changing either the KeyName or the ValueName property. + + + Type '{2}' contains two members '{0}' 'and '{1}' with the same name '{3}'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using EnumMemberAttribute attribute. + + + Type '{2}' contains two members '{0}' 'and '{1}' with the same data member name '{3}'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using DataMemberAttribute attribute. + + + Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'. + + + Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'. + + + {0}. Encountered '{1}' with name '{2}', namespace '{3}'. + + + Enum type '{0}' cannot have the IsReference setting of '{1}'. Either change the setting to '{2}', or remove it completely. + + + There was an error deserializing the object {0}. {1} + + + Error in line {0} position {1}. + + + There was an error checking start element of object {0}. {1} + + + There was an error serializing the object {0}. {1} + + + of type {0} + + + There was an error writing end element of object {0}. {1} + + + There was an error writing start element of object {0}. {1} + + + Maximum number of items that can be serialized or deserialized in an object graph is '{0}'. + + + Expecting element '{1}' from namespace '{0}'. + + + Expecting state '{0}' when ReadObject is called. + + + Expecting End'{0}'. + + + Expecting state '{0}'. + + + The data contract name '{0}' for type '{1}' has a curly brace '{{' that is not matched with a closing curly brace. Curly braces have special meaning in data contract names - they are used to customize the naming of data contracts for generic types. + + + In the data contract name for type '{1}', there are curly braces with '{0}' inside, which is an invalid value. Curly braces have special meaning in data contract names - they are used to customize the naming of data contracts for generic types. Based on the number of generic parameters this type has, the contents of the curly braces must either be a number between 0 and '{2}' to insert the name of the generic parameter at that index or the '#' symbol to insert a digest of the generic parameter namespaces. + + + The IsReference setting for type '{0}' is '{1}', but the same setting for its parent class '{2}' is '{3}'. Derived types must have the same value for IsReference as the base type. Change the setting on type '{0}' to '{3}', or on type '{2}' to '{1}', or do not set IsReference explicitly. + + + Property '{1}' in type '{0}' cannot be serialized because serialization of indexed properties is not supported. + + + Type '{0}' cannot have CollectionDataContractAttribute attribute ItemName set to null or empty string. + + + Type '{0}' cannot have CollectionDataContractAttribute attribute KeyName set to null or empty string. + + + The collection data contract type '{0}' specifies '{1}' for the KeyName property. This is not allowed since the type is not IDictionary. Remove the setting for the KeyName property. + + + Type '{0}' cannot have CollectionDataContractAttribute attribute Name set to null or empty string. + + + Type '{0}' cannot have CollectionDataContractAttribute attribute Namespace set to null. + + + Type '{0}' cannot have CollectionDataContractAttribute attribute ValueName set to null or empty string. + + + The collection data contract type '{0}' specifies '{1}' for the ValueName property. This is not allowed since the type is not IDictionary. Remove the setting for the ValueName property. + + + Type '{0}' with CollectionDataContractAttribute attribute is an invalid collection type since it + + + Type '{0}' is an invalid collection type since it + + + Type '{0}' cannot have DataContractAttribute attribute Name set to null or empty string. + + + Type '{0}' cannot have DataContractAttribute attribute Namespace set to null. + + + Member '{0}' in type '{1}' cannot have DataMemberAttribute attribute Name set to null or empty string. + + + '{0}' in type '{1}' cannot have EnumMemberAttribute attribute Value set to null or empty string. + + + Invalid enum value '{0}' cannot be deserialized into type '{1}'. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute. + + + Enum value '{0}' is invalid for type '{1}' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute. + + + Type '{0}' cannot have MethodName on XmlSchemaProviderAttribute attribute set to null or empty string. + + + CLR namespace '{0}' cannot have ContractNamespace set to null. + + + Member '{0}.{1}' cannot be serialized since it is neither a field nor a property, and therefore cannot be marked with the DataMemberAttribute attribute. Remove the DataMemberAttribute attribute from the '{1}' member. + + + Method '{0}.{1}()' returns a non-null value. The return value must be null since IsAny + + + Type '{0}' is not a valid serializable type. + + + Method '{0}.{1}()' returns '{2}'. The return type must be compatible with '{3}'. + + + Invalid Size '{0}'. Must be non-negative integer. + + + XML data contract Name for type '{0}' cannot be set to null or empty string. + + + Invalid Id '{0}'. Must not be null or empty. + + + Invalid Ref '{0}'. Must not be null or empty. + + + A null value cannot be serialized at the top level for IXmlSerializable root type '{0}' since its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct. + + + An object of type '{0}' cannot be serialized at the top level for IXmlSerializable root type '{1}' since its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct. + + + Type '{0}' cannot specify an XmlRootAttribute attribute because its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct. + + + An internal error has occurred. '{0}' is not assignable from '{1}' - error generating code for serialization. + + + '{0}.{1}' has the IsRequired setting of '{2}. However, '{0}' has the IsReference setting of '{2}', because either it is set explicitly, or it is derived from a base class. Set IsRequired on '{0}.{1}' to false, or disable IsReference on '{0}'. + + + Type '{0}' cannot be IXmlSerializable and have CollectionDataContractAttribute attribute. + + + Type '{0}' cannot be IXmlSerializable and have DataContractAttribute attribute. + + + This method cannot be called from IXmlSerializable implementations. + + + IXmlSerializable.WriteXml method of type '{0}' did not close all open tags. Verify that the IXmlSerializable implementation is correct. + + + IXmlSerializable Type '{0}' must have default constructor. + + + IXmlSerializable.WriteXml method of type '{0}' attempted to close too many tags. Verify that the IXmlSerializable implementation is correct. + + + Method name specified by KnownTypeAttribute attribute on type '{0}' cannot be the empty string. + + + KnownTypeAttribute attribute on type '{1}' specifies a method named '{0}' to provide known types. Static method '{0}()' was not found on this type. Ensure that the method exists and is marked as static. + + + KnownTypeAttribute attribute on type '{0}' specifies a method named '{1}' to provide known types. The return type of this method is invalid because it is not assignable to IEnumerable<Type>. Ensure that the method exists and has a valid signature. + + + Type '{0}': If a KnownTypeAttribute attribute specifies a method it must be the only KnownTypeAttribute attribute on that type. + + + Method specified by KnownTypeAttribute attribute on type '{0}' does not expose valid types. + + + KnownTypeAttribute attribute on type '{0}' contains no data. + + + Method specified by KnownTypeAttribute attribute on type '{0}' returned null. + + + The maximum array length ({0}) has been exceeded while reading XML data for array of type '{1}'. + + + Type '{0}' does not have a static method '{1}' that takes a parameter of type 'System.Xml.Schema.XmlSchemaSet' as specified by the XmlSchemaProviderAttribute attribute. + + + Invalid XML encountered. The same Id value '{0}' is defined more than once. Multiple objects cannot be deserialized using the same Id. + + + An internal error has occurred. No conversion is possible to '{0}' - error generating code for serialization. + + + Collection type '{0}' doesn't have default constructor. + + + No get method for property '{1}' in type '{0}'. + + + No set method for property '{1}' in type '{0}'. + + + One of the known types provided to the serializer via '{0}' argument was invalid because it was null. All known types specified must be non-null values. + + + The get-only collection of type '{0}' returned a null value. The input stream contains collection items which cannot be added if the instance is null. Consider initializing the collection either in the constructor of the object or in the getter. + + + An internal error has occurred. Object table overflow. This could be caused by serializing or deserializing extremely large object graphs. + + + Invalid number of parameters to call method '{0}'. Expected '{1}' parameters, but '{2}' were provided. + + + The collection data contract type '{0}' cannot be deserialized because the method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The collection data contract type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The collection data contract type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be serialized because the OnSerializing method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be serialized because the OnSerialized method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be deserialized because the OnDeserializing method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be deserialized because the OnDeserialized method '{1}' is not public. Making the method public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be serialized because the member '{1}' is not public. Making the member public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be deserialized because the member '{1}' is not public. Making the member public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be serialized because the property '{1}' does not have a public getter. Adding a public getter will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' cannot be deserialized because the property '{1}' does not have a public setter. Adding a public setter will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The data contract type '{0}' is not serializable because it is not public. Making the type public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The IXmlSerializable type '{0}' is not serializable in partial trust because it is not public. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The IXmlSerializable type '{0}' cannot be deserialized because it does not have a public parameterless constructor. Adding a public parameterless constructor will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. + + + The Type '{0}' must have a parameterless constructor. + + + Type '{0}' cannot inherit from a type that is not marked with DataContractAttribute or SerializableAttribute. Consider marking the base type '{1}' with DataContractAttribute or SerializableAttribute, or removing them from the derived type. + + + Quota must be a positive value. + + + The '{0}' quota is readonly. + + + Cannot copy XmlDictionaryReaderQuotas. Target is readonly. + + + Member {0} in type {1} cannot be serialized. This exception is usually caused by trying to use a null value where a null value is not allowed. The '{0}' member is set to its default value (usually null or zero). The member's EmitDefault setting is 'false', indicating that the member should not be serialized. However, the member's IsRequired setting is 'true', indicating that it must be serialized. This conflict cannot be resolved. Consider setting '{0}' to a non-default value. Alternatively, you can change the EmitDefaultValue property on the DataMemberAttribute attribute to true, or changing the IsRequired property to false. + + + An object of type '{0}' which derives from DataContractResolver returned false from its TryResolveType method when attempting to resolve the name for an object of type '{1}', indicating that the resolution failed. Change the TryResolveType implementation to return true. + + + An object of type '{0}' which derives from DataContractResolver returned a null typeName or typeNamespace but not both from its TryResolveType method when attempting to resolve the name for an object of type '{1}'. Change the TryResolveType implementation to return non-null values, or to return null values for both typeName and typeNamespace in order to serialize as the declared type. + + + Multi-dimensional arrays are not supported. + + + Type '{0}' has more than one CollectionDataContractAttribute attribute. + + + Type '{0}' has more than one DataContractAttribute attribute. + + + Member '{0}.{1}' has more than one DataMemberAttribute attribute. + + + Member '{0}.{1}' has more than one EnumMemberAttribute attribute. + + + Member '{0}.{1}' has more than one IgnoreDataMemberAttribute attribute. + + + Type '{0}' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required. + + + An internal error has occurred. Unexpected contract type '{0}' for type '{1}' encountered. + + + '{0}' '{1}' from namespace '{2}' is not expected. Expecting element '{3}'. + + + Unexpected end of file. + + + Internal Error: Unrecognized constant type {0}. + + + The value of this argument must be non-negative. + + + ValueType '{0}' cannot be null. + + + Data contract '{0}' from namespace '{1}' is a value type and cannot have base contract '{2}' from namespace '{3}'. + + + ValueType '{0}' cannot have id. + + + Value type '{0}' cannot have the IsReference setting of '{1}'. Either change the setting to '{2}', or remove it completely. + + + ValueType '{0}' cannot have ref to another object. + + + Only Element nodes have attributes. + + + Element {0} from namespace {1} cannot have child contents to be deserialized as an object. Please use XElement to deserialize this pattern of XML. + + + The value '{0}' cannot be parsed as the type '{1}'. + + + The value cannot be parsed as the type '{0}'. + + + Start element expected. Found {0}. + + + WriteState '{0}' not valid. Caller must write start element before serializing in contentOnly mode. + + + {0}.{1}' is not marked with OptionalFieldAttribute, thus indicating that it must be serialized. However, '{0}' derives from a class marked with DataContractAttribute and an IsReference setting of '{2}'. It is not possible to have required data members on IsReference classes. Either decorate '{0}.{1}' with OptionalFieldAttribute, or disable the IsReference setting on the appropriate parent class. + + + The specified offset exceeds the buffer size ({0} bytes). + + + The specified size exceeds the remaining buffer space ({0} bytes). + + + The value of this argument must fall within the range {0} to {1}. + + + Array too small. Must be able to hold at least {0}. + + + An asynchronous operation is already in progress. + + + Base64 sequence length ({0}) not valid. Must be a multiple of 4. + + + The characters '{0}' at offset {1} are not a valid Base64 sequence. + + + BinHex sequence length ({0}) not valid. Must be a multiple of 2. + + + The characters '{0}' at offset {1} are not a valid BinHex sequence. + + + High surrogate char '0x{0}' not valid. High surrogate chars range from 0xD800 to 0xDBFF. + + + Low surrogate char '0x{0}' not valid. Low surrogate chars range from 0xDC00 to 0xDFFF. + + + Surrogate char '0x{0}' not valid. Surrogate chars range from 0x10000 to 0x10FFFF. + + + The empty string is not a valid local name. + + + Array too small. + + + Array too small. Length of available data must be at least {0}. + + + Unrecognized Byte Order Mark. + + + Base64 encoded data expected. Found {0}. + + + CData elements not valid at top level of an XML document. + + + ']]>' not valid in text node content. + + + The value '{0}' cannot be represented with the type '{1}'. + + + An XML declaration with an encoding is required for all non-UTF8 documents. + + + Version not found in XML declaration. + + + An XML declaration is required for all non-UTF8 documents. + + + No characters can appear before the XML declaration. + + + XmlDictionaryString IDs must be in the range from {0} to {1}. + + + XmlDictionaryString ID {0} not defined in the XmlBinaryReaderSession. + + + XmlDictionaryString ID {0} not defined in the static dictionary. + + + Duplicate attribute found. Both '{0}' and '{1}' are from the namespace '{2}'. + + + The empty namespace requires a null or empty prefix. + + + The encoding in the declaration '{0}' does not match the encoding of the document '{1}'. + + + XML encoding not supported. + + + End element '{0}' from namespace '{1}' expected. Found {2}. + + + No corresponding start element is open. + + + The expected encoding '{0}' does not match the actual encoding '{1}'. + + + cdata '{0}' + + + comment '{0}' + + + element '{0}' from namespace '{1}' + + + end element '{0}' from namespace '{1}' + + + end of file + + + node {0} + + + text '{0}' + + + Non-empty start element expected. Found {0}. + + + Non-empty start element '{0}' from namespace '{1}' expected. Found {2}. + + + Non-empty start element '{0}' expected. Found {1}. + + + ID already defined. + + + The specified key already exists in the dictionary. + + + Text cannot be written outside the root element. + + + Invalid byte encoding. + + + Character reference not valid. + + + XML comments cannot contain '--' or end with '-'. + + + XML declaration can only be written at the beginning of the document. + + + Cannot call '{0}' while Depth is '{1}'. + + + XML encoding must be 'UTF-8'. + + + Characters with hexadecimal values 0xFFFE and 0xFFFF are not valid. + + + The input source is not correctly formatted. + + + ID must be > + + + The reader cannot be advanced. + + + A prefix cannot be defined while WriteState is '{0}'. + + + Expected XML qualified name. Found '{0}'. + + + The data at the root level is invalid. + + + 'standalone' value in declaration must be 'yes' or 'no'. + + + UniqueId cannot be zero length. + + + '{0}' contains invalid UTF8 bytes. + + + XML version must be '1.0'. + + + '{0}' cannot be called while WriteState is '{1}'. + + + The byte 0x{0} is not valid at this location. + + + '{0}' is not a valid xml:space value. Valid values are 'default' and 'preserve'. + + + Line {0}, position {1}. + + + Malformed XML declaration. + + + The maximum array length quota ({0}) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. + + + The 'maximum bytes per Read operation' quota ({0}) has been exceeded while reading XML data. Long element start tags (consisting of the element name, attribute names and attribute values) may trigger this quota. This quota may be increased by changing the MaxBytesPerRead property on the XmlDictionaryReaderQuotas object used when creating the XML reader. + + + The maximum read depth ({0}) has been exceeded because XML data being read has more levels of nesting than is allowed by the quota. This quota may be increased by changing the MaxDepth property on the XmlDictionaryReaderQuotas object used when creating the XML reader. + + + The maximum string content length quota ({0}) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. + + + This XmlWriter implementation does not support the '{0}' method. + + + The surrogate pair is invalid. Missing a low surrogate character. + + + There are multiple root elements. + + + The namespace '{0}' is not defined. + + + Nested arrays are not supported. + + + The document does not have a root element. + + + Only one root element is permitted per document. + + + Only whitespace characters can be written with this method. + + + Only a single typed value may be written inside an attribute or content. + + + The prefix '{0}' is bound to the namespace '{1}' and cannot be changed to '{2}'. + + + Processing instructions (other than the XML declaration) and DTDs are not supported. + + + Prefixes beginning with 'xml' (regardless of casing) are reserved for use by XML. + + + Whitespace must appear between attributes. + + + The namespace '{1}' can only be bound to the prefix '{0}'. + + + The prefix '{0}' can only be bound to the namespace '{1}'. + + + Start element '{0}' from namespace '{1}' expected. Found {2}. + + + Start element '{0}' expected. Found {1}. + + + Start element '{0}' does not match end element '{1}'. + + + The token '{0}' was expected but found '{1}'. + + + The prefix '{0}' is not defined. + + + No matching start tag for end element. + + + Unexpected end of file. Following elements are not closed: {0}. + + + The XmlWriter is closed. + + + '{0}' is an XML type and cannot be serialized when assigned to an interface type that does not implement IXmlSerializable ('{1}'.) + + + '{0}' is a collection type and cannot be serialized when assigned to an interface type that does not implement IEnumerable ('{1}'.) + + + Invalid byte encoding. + + + The data contract type '{0}' is not serializable with DataContractJsonSerializer because the data member '{1}' is duplicated in its type hierarchy. + + + The type '{0}' cannot be serialized to JSON because its IsReference setting is '{1}'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type. + + + Type '{0}' cannot be serialized, serialization code for the type is missing. Consult the SDK documentation for adding it as a root serialization type. + + + The XML encountered when deserializing extension data is invalid. + + + An internal error has occurred. ExtensionDataReader is in an invalid state. + + + DataContractJsonSerializer does not support objects of type '{0}'. + + + Collection interface type '{0}' is being used as a get-only property and does not have an Add method. Consider adding a setter to the property or using a collection data contract that does have an Add method - for example IList or ICollection<T>. + + + The attribute 'type' must have one of the following strings as its values: 'string', 'number', 'array', 'object', 'null', or 'boolean'. Encountered unexpected value '{0}' + + + DateTime content '{0}' does not start with '{1}' and end with '{2}' as required for JSON. + + + A user callback threw an exception. Check the exception stack and inner exception to determine the callback that failed. + + + Encountered unexpected character '{0}'. + + + The specified offset exceeds the buffer size ({0} bytes). + + + The specified size exceeds the remaining buffer space ('{0}' bytes). + + + Encountered invalid character '{0}'. + + + Characters with hexadecimal values 0xFFFE and 0xFFFF are not valid. + + + DateTime values that are greater than DateTime.MaxValue or smaller than DateTime.MinValue when converted to UTC cannot be serialized to JSON. + + + To write JSON arrays, use XML writer methods to write the attribute type='array' followed by methods like WriteStartElement (with the local name 'item'), WriteAttributeString, and WriteEndElement to write the JSON array items. + + + This XmlDictionaryWriter implementation does not support the '{0}' method. + + + There is no open attribute. + + + Encountered unexpected namespace '{0}'. The namespace must be empty. + + + No corresponding start element is open. + + + Cannot call {0} while an attribute is being written. + + + You must write an attribute '{0}'='{1}' after writing the attribute with local name '{2}'. + + + Processing instructions (other than the XML declaration) are not supported. + + + XML declaration can only be written at the beginning of the document. + + + The empty string is not a valid local name in JSON. + + + Encountered unexpected prefix '{0}'. The prefix must be null or empty. + + + WriteStartElement must be called at least once before WriteStartAttribute may be called. + + + Cannot write attribute with local name '{0}' multiple times. + + + Attempted to write an attribute with local name '{0}' after writing the attribute '{1}'='{2}'. An attribute with local name '{0}' may be written only after writing the attribute '{1}'='{3}'. + + + Encountered unexpected attribute local name '{0}'. 'type' and '__type' are the only allowed local names for attributes. 'type' can be used to influence how data is written; its valid values are 'object', 'string', 'number', 'null', 'boolean', and 'array'. '__type' can be used to provide type hint information to the writer. + + + '{0}' cannot be called while WriteState is '{1}'. + + + This XmlDictionaryWriter implementation does not support the writing of multiple root elements. + + + Encountered invalid root element name '{0}'. '{1}' is the only allowed root element name. + + + WriteStartElement cannot be called immediately after WriteStartElement without writing the 'type'='array' or 'type='object' attribute. + + + Encountered unexpected element local name '{0}' for item in collection. '{1}' is the only valid local name for elements in a collection. + + + WriteStartElement can be called at only the start of a document or immediately after calling WriteEndElement. + + + Unexpected character '{0}'. '{1}' can write only whitespace characters. + + + The writer is closed. + + + Cannot write a CLR value that maps to number, array, object, true, false or null in JSON after a string value has been written. + + + To write attribute values with this XmlDictionaryWriter implementation, you must write either string or char[] values. + + + Attempted to write an attribute '{0}'='{1}' after writing the attribute with local name '{2}'. The attribute with local name '{2}' is only valid with an attribute '{0}'='{3}'. + + + Cannot write content while an attribute is being written. + + + Attempted to write text after writing attribute type='{0}'. Text may be written only after the attributes type='number', type='boolean', or type='string'. + + + Nested arrays are not supported. + + + Encoding not supported in JSON. UTF-8, Unicode, and BigEndianUnicode are the only supported encodings. + + + The expected encoding '{0}' does not match the actual encoding '{1}'. + + + Unexpected end of file. + + + Assembly '{0}' is not found. + + + The deserializer cannot load the type to deserialize because type '{1}' could not be found in assembly '{0}'. Check that the type being serialized has the same contract as the type being deserialized and the same assembly is used. + + + XML '{2}' '{3}:{4}' does not contain expected attribute '{0}:{1}'. The deserializer has no knowledge of which type to deserialize. Check that the type being serialized has the same contract as the type being deserialized. + + + The data contract type '{0}' cannot be deserialized because the data member '{1}' was found more than once in the input. + + + The data contract type '{0}' cannot be deserialized because the required data members '{1}' were not found. + + + The data contract type '{0}' cannot be deserialized because the required data member '{1}' was not found. + + + DataContractJsonSerializer does not support data members of type '{0}'. Consider using int, System.Object, or a concrete enum definition instead. + + + The dictionary of type '{0}' cannot be deserialized as a simple dictionary because its key type '{1}' does not have a public static Parse method. + + + Using surrogates with get-only collection properties is not supported. Consider removing the surrogate associated with '{0}'. + + + Object graph of type '{0}' with Id '{2}' contains a reference to itself. The object has been replaced with a new object of type '{1}' either because it implements IObjectReference or because it is surrogated. The serializer does not support fixing up the nested reference to the new object and cannot deserialize this object. Consider changing the object to remove the nested self-reference. + + + Type '{0}' is a recursive collection data contract which is not supported. Consider modifying the definition of collection '{0}' to remove references to itself. + + + Type '{0}' is not a valid XML type. + + + DataContract with name '{0}' and namespace '{1}' cannot be added to DataContractSet since another contract with the same data contract name is already present and the contracts are not equivalent. + + + DataContract for type '{0}' cannot be added to DataContractSet since type '{1}' with the same data contract name '{2}' in namespace '{3}' is already present and the contracts are not equivalent. + + + Type '{0}' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types. + + + Cannot export null assembly provided via '{0}' parameter. + + + Cannot export null type provided via KnownTypesCollection. + + + Cannot export null type provided via '{0}' parameter. + + + Cannot find a path to the member when generating the XPath query. + + + Stream returned by IStreamProvider cannot be null. + + + Type '{0}' has set its ISerializable assembly name to "0". "0" is an invalid assembly name. Consider using the full name of mscorlib if you would like your type to be deserialized in that assembly. + + + Only classes can be generated as ISerializable. + + + Type '{0}' cannot be ISerializable and have DataContractAttribute attribute. + + + The constructor with parameters (SerializationInfo, StreamingContext) is not found in ISerializable type '{0}'. + + + DataContractJsonSerializer does not support the setting of the FullTypeName of the object to be serialized to a value other than the default FullTypeName. Attempted to serialize object with full type name '{0}' and default full type name '{1}'. + + + Interface type '{0}' cannot be created. Consider replacing with a non-interface serializable type. + + + Array Size '{0}' is not equal to the number of elements found '{1}'. + + + Invalid IExtensibleDataObject. Both '{0}' and '{1}' in type '{2}' provide property setter. + + + IExtensibleDataObject property setter '{1}' in type '{0}' must return void. + + + IExtensibleDataObject property setter '{1}' in type '{0}' must have a single parameter of type '{2}'. + + + Type '{0}' does not have DataContractAttribute attribute and therefore cannot support IExtensibleDataObject. + + + JsonObjectDataContract.ParseJsonNumber shouldn't return a TypeCode that we're not expecting. + + + An internal error has occurred. Could not load serialization schema. Consider providing schema with namespace '{0}'. + + + Schema type '{0}' returned by CLR type '{1}' is not found in the XmlSchemaSet. + + + Method '{0}.GetSchema()' must return a schema with a valid Id. + + + The Message Transmission Optimization Mechanism (MTOM) message encoding is not supported on this platform. + + + System.Runtime.Serialization.NetDataContractSerializer is not supported on this platform. + + + The implementation of the function requires System.Runtime.Serialization.IDataContractSurrogate which is not supported on this platform. + + + The implementation of the function requires System.Runtime.Serialization.SchemaImporter which is not supported on this platform. + + + The canonicalization process is not supported on this platform. + + + Factory type '{0}' for ISerializable type '{1}' must also be ISerializable. + + + Canonicalization already started. + + + Canonicalization not started. + + + The combined length of the prefix and namespace must not be greater than {0}. + + + The inclusive namespace prefix collection cannot contain null as one of the items. + + + Failed to create Delegate for method '{0}' of type '{1}'. + + + Invalid assembly format: {0} + + + IsAny not supported by NetDataContractSerializer: {0} + + + ArrayTypeIsNotSupported: {0} + + + ClassDataContractReturnedForGetOnlyCollection: {0} + + + InvalidDataNode: {0} + + + InvalidEnumBaseType: {0}, {1}, {2}, {3} + + + InvalidPrimitiveType: {0} + + + IsReferenceGetOnlyCollectionsNotSupported: {0}, {1} + + + KnownTypeConfigClosedGenericDeclared: {0} + + + PartialTrustISerializableNoPublicConstructor: {0} + + + ReadOnlyClassDeserialization: {0} + + + ReadOnlyCollectionDeserialization: {0} + + + ReferencedCollectionTypesCannotContainNull + + + ReferencedTypesCannotContainNull + + + SurrogatesWithGetOnlyCollectionsNotSupported: {0}, {1}, {2} + + + TypeCannotBeForwardedFrom: {0}, {1}, {2} + + + TypeMustBeConcrete: {0} + + + XmlMaxArrayLengthOrMaxItemsQuotaExceeded: {0} + + + GetRealObjectReturnedNull: {0} + + + Cannot import invalid schemas. Compilation on the XmlSchemaSet failed. + + + Cannot import null XmlSchema contained in XmlSchemaSet specified via parameter. + + + Cannot import type for null XmlQualifiedName specified via parameter. + + + A unique name cannot be computed for '{0}' because there are already Int32.MaxValue types of with the same name. + + + Invalid type specified. Type with name '{0}' not found in schema with namespace '{1}'. + + + Redefine is not supported. + + + Simple types with <union> content are not supported. + + + Complex types with simple content extension are not supported. + + + Complex type with mixed content is not supported. + + + Complex types derived by restriction not supported. + + + The root particle must be a sequence. + + + 'minOccurs' on the root sequence must be 1. + + + 'maxOccurs' on the root sequence must be 1. + + + It is not ISerializable but its base type '{0}' in namespace '{1}' is ISerializable. + + + The root sequence must contain only local elements. Group ref, choice, any and nested sequences are not supported. + + + '{0}' is an invalid value for IsValueType annotation. {1} + + + One of its base types, '{0}' from namespace '{1}' is not ISerializable. + + + Derived ISerializable types cannot contain any particles. + + + It does not contain root sequence with a wildcard element <any>. + + + Its root sequence contains more than one particle. + + + 'minOccurs' on the wildcard element must be '{0}'. + + + 'maxOccurs' on the wildcard element must be '{0}'. + + + Namespace on the wildcard element must be '{0}'. + + + ProcessContents on the wildcard element must be '{0}'. + + + It does not reference attribute '{0}' from namespace '{1}'. + + + Cannot import type '{0}' in namespace '{1}' as its base type because derived type is ISerializable but the base type is not ISerializable. + + + Type '{0}' in namespace '{1}' cannot be used as the base type of a data contract type, because it itself does not have a data contract. Consider marking type '{0}' with the DataContractAttribute attribute. + + + Anonymous type in element '{0}' from namespace '{1}' is not supported. + + + The global element found in the schema with same name references a different type '{0}' in namespace '{1}'. Data contract types must have the same name as their root element name. Consider removing the global element or changing its type. + + + 'minOccurs' on element '{0}' must be 0 or 1. + + + 'maxOccurs' on element '{0}' must be 1. + + + Form on element '{0}' must be qualified. + + + Ref to element '{0}' in '{1}' namespace is not supported. + + + Annotation for element {0} in type {1} from namespace {2} specifies EmitDefaultValue as 'true'. This requires the element to be either nillable or the element's type must be a value type. + + + The type contains two elements with the same name '{0}'. Multiple elements with the same name in one type are not supported because members marked with DataMemberAttribute attribute must have unique names. + + + Invalid '{0}' annotation in type '{1}' from namespace '{2}'. Attribute '{3}' not present. + + + Form for element '{0}' must be qualified. + + + It is an invalid dictionary type. Element '{0}' must reference a complex type containing a sequence with two required elements. Either fix the schema or remove the IsDictionary annotation. + + + It is an invalid dictionary type since element '{0}' references a type from a different namespace '{1}'. Either fix the schema or remove the IsDictionary annotation. + + + '{0}' is an invalid value for IsDictionary annotation. {1} + + + Simple type list must contain an anonymous type specifying enumeration facets. + + + Anonymous type with <union>. cannot be used to create Flags enumeration because it is not a valid enum type. + + + Anonymous type with <list> cannot be used to create Flags enumeration because it is not a valid enum type. + + + Anonymous type with <restriction> cannot be used to create Flags enumeration because it is not a valid enum type. + + + Facets other than enumeration facets are not supported. + + + Enumeration facets without 'value' are not supported. + + + Simple type restriction must specify a base type. + + + Annotation for generic type '{0}' did not have attribute '{1}'. + + + Annotation for generic type '{2}' has an invalid element '{0}' from namespace '{1}'. + + + Annotation element '{0}' from namespace '{1}' for generic type '{2}' has an invalid value '{3}' for attribute '{4}'. Expecting value to be of type '{5}'. + + + Nested level on annotation elements '{0}' from namespace '{1}' for generic type '{2}' must be in increasing order. + + + The type cannot have 'abstract' set to 'true'. + + + The element cannot have 'abstract' set to 'true'. + + + Default value on element '{0}' is not supported. + + + Fixed value on element '{0}' is not supported. + + + Substitution group on element '{0}' is not supported. + + + 'anyAttribute' is not supported. + + + Attributes must be optional and from namespace '{0}'. + + + The type contains two attributes with the same name '{0}'. Multiple attributes with the same name in one type are not supported. + + + Annotation '{0}' from namespace '{1}' has an invalid element '{2}' from namespace '{3}'. Expecting text. + + + Type '{0}' in namespace '{1}' cannot be imported. {2} + + + Array type '{0}' in namespace '{1}' cannot be imported. {2} + + + Enum type '{0}' in namespace '{1}' cannot be imported. {2} + + + ISerializable type '{0}' in namespace '{1}' cannot be imported. '{2}' + + + {0} Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer. + + + (matching) + + + (not matching) + + + List of referenced collection types contains more than one type with same data contract name. Include only one of the following types. Only matching types can be valid references: {0} + + + List of referenced types contains more than one type with same data contract name. Need to exclude all but one of the following types. Only matching types can be valid references: {0} + + + List of referenced collection types contains more than one type with data contract name '{0}' in namespace '{1}'. Include only one of the following types. Only matching types can be valid references: {2} + + + List of referenced types contains more than one type with data contract name '{0}' in namespace '{1}'. Need to exclude all but one of the following types. Only matching types can be valid references: {2} + + \ No newline at end of file diff --git a/NetDataContractSerializer.sln b/NetDataContractSerializer.sln new file mode 100644 index 0000000..04917c8 --- /dev/null +++ b/NetDataContractSerializer.sln @@ -0,0 +1,123 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.152 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Compat.Private.Serialization", "Compat.Private.Serialization\Compat.Private.Serialization.csproj", "{1F4EB25F-3A60-45DC-A547-47847B194B32}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Debug|x86.ActiveCfg = Debug|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Debug|x86.Build.0 = Debug|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Release|Any CPU.Build.0 = Release|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Release|x86.ActiveCfg = Release|Any CPU + {AB2CF6F8-831A-440A-B90A-4C1EB3437A15}.Release|x86.Build.0 = Release|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Debug|x86.ActiveCfg = Debug|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Debug|x86.Build.0 = Debug|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Release|Any CPU.Build.0 = Release|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Release|x86.ActiveCfg = Release|Any CPU + {998759D0-5251-44FB-B5ED-331D28751F1C}.Release|x86.Build.0 = Release|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Debug|x86.ActiveCfg = Debug|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Debug|x86.Build.0 = Debug|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Release|Any CPU.Build.0 = Release|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Release|x86.ActiveCfg = Release|Any CPU + {A2AEAA66-FA33-437C-BC21-E644A4865543}.Release|x86.Build.0 = Release|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Debug|x86.ActiveCfg = Debug|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Debug|x86.Build.0 = Debug|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Release|Any CPU.Build.0 = Release|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Release|x86.ActiveCfg = Release|Any CPU + {624AA825-698D-490D-8C71-1126035E96F2}.Release|x86.Build.0 = Release|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Debug|x86.ActiveCfg = Debug|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Debug|x86.Build.0 = Debug|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Release|Any CPU.Build.0 = Release|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Release|x86.ActiveCfg = Release|Any CPU + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3}.Release|x86.Build.0 = Release|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Debug|x86.Build.0 = Debug|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Release|Any CPU.Build.0 = Release|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Release|x86.ActiveCfg = Release|Any CPU + {4D9C3EA3-30AD-43C2-835E-166A42872C03}.Release|x86.Build.0 = Release|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Debug|x86.ActiveCfg = Debug|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Debug|x86.Build.0 = Debug|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Release|Any CPU.Build.0 = Release|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Release|x86.ActiveCfg = Release|Any CPU + {35BD700E-2888-4B11-ABFA-D49371E9ECDE}.Release|x86.Build.0 = Release|Any CPU + {C1853B29-C445-4098-81A5-3ADB633DF213}.Debug|Any CPU.ActiveCfg = Debug|x86 + {C1853B29-C445-4098-81A5-3ADB633DF213}.Debug|x86.ActiveCfg = Debug|x86 + {C1853B29-C445-4098-81A5-3ADB633DF213}.Debug|x86.Build.0 = Debug|x86 + {C1853B29-C445-4098-81A5-3ADB633DF213}.Release|Any CPU.ActiveCfg = Release|x86 + {C1853B29-C445-4098-81A5-3ADB633DF213}.Release|x86.ActiveCfg = Release|x86 + {C1853B29-C445-4098-81A5-3ADB633DF213}.Release|x86.Build.0 = Release|x86 + {302B8E43-8366-4E01-B35F-CB0C97902806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Debug|Any CPU.Build.0 = Debug|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Debug|x86.ActiveCfg = Debug|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Debug|x86.Build.0 = Debug|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Release|Any CPU.ActiveCfg = Release|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Release|Any CPU.Build.0 = Release|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Release|x86.ActiveCfg = Release|Any CPU + {302B8E43-8366-4E01-B35F-CB0C97902806}.Release|x86.Build.0 = Release|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Debug|x86.ActiveCfg = Debug|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Debug|x86.Build.0 = Debug|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Release|Any CPU.Build.0 = Release|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Release|x86.ActiveCfg = Release|Any CPU + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9}.Release|x86.Build.0 = Release|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Debug|x86.ActiveCfg = Debug|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Debug|x86.Build.0 = Debug|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Release|Any CPU.Build.0 = Release|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Release|x86.ActiveCfg = Release|Any CPU + {1F4EB25F-3A60-45DC-A547-47847B194B32}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {624AA825-698D-490D-8C71-1126035E96F2} = {A3A5753A-2E8F-4970-B7BB-AA59E3C49247} + {29E0781B-FEED-47A4-B5D0-F3F47C642DE3} = {76D59EF6-6073-4E0A-B2CC-A69FCF66557A} + {4D9C3EA3-30AD-43C2-835E-166A42872C03} = {6EC5CC4A-E47A-4945-B986-645EEE26E6DD} + {35BD700E-2888-4B11-ABFA-D49371E9ECDE} = {6EC5CC4A-E47A-4945-B986-645EEE26E6DD} + {C1853B29-C445-4098-81A5-3ADB633DF213} = {76D59EF6-6073-4E0A-B2CC-A69FCF66557A} + {302B8E43-8366-4E01-B35F-CB0C97902806} = {76D59EF6-6073-4E0A-B2CC-A69FCF66557A} + {0E9962A0-1883-4D05-A162-02BE32F9B6C4} = {76D59EF6-6073-4E0A-B2CC-A69FCF66557A} + {DAE39861-D2F3-419B-9E8A-E783F0C5E89E} = {0E9962A0-1883-4D05-A162-02BE32F9B6C4} + {6EC5CC4A-E47A-4945-B986-645EEE26E6DD} = {DAE39861-D2F3-419B-9E8A-E783F0C5E89E} + {AB081229-928D-4718-A905-E35062D720CB} = {0E9962A0-1883-4D05-A162-02BE32F9B6C4} + {5A0F307E-BCA1-4BD7-9A5B-CF77607CA079} = {AB081229-928D-4718-A905-E35062D720CB} + {DAFF1345-4EB5-449E-94CE-1064C9E98FA9} = {5A0F307E-BCA1-4BD7-9A5B-CF77607CA079} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FB69BC62-AC69-4BB8-AB33-DF7E370C9F5B} + EndGlobalSection +EndGlobal