// // System.Xml.Serialization.SerializationCodeGenerator.cs: // // Authors: // Lluis Sanchez Gual (lluis@ximian.com) // Atsushi Enomoto (atsushi@ximian.com) // // (C) 2002, 2003 Ximian, Inc. http://www.ximian.com // Copyright (C) 2006 Novell, Inc. // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System.IO; using System.Reflection; using System.Xml.Serialization; using System.Collections; using System.Globalization; using System.Text; using HookDir = System.Xml.Serialization.XmlMappingAccess; namespace System.Xml.Serialization { internal class SerializationCodeGenerator { XmlMapping _typeMap; SerializationFormat _format; TextWriter _writer; int _tempVarId = 0; int _indent = 0; Hashtable _uniqueNames = new Hashtable(); int _methodId = 0; SerializerInfo _config; ArrayList _mapsToGenerate = new ArrayList (); ArrayList _fixupCallbacks; ArrayList _referencedTypes = new ArrayList (); GenerationResult[] _results; GenerationResult _result; XmlMapping[] _xmlMaps; CodeIdentifiers classNames = new CodeIdentifiers (); public SerializationCodeGenerator (XmlMapping[] xmlMaps): this (xmlMaps, null) { } public SerializationCodeGenerator (XmlMapping[] xmlMaps, SerializerInfo config) { _xmlMaps = xmlMaps; _config = config; } public SerializationCodeGenerator (XmlMapping xmlMap, SerializerInfo config) { _xmlMaps = new XmlMapping [] {xmlMap}; _config = config; } public static void Generate (string configFileName, string outputPath) { SerializationCodeGeneratorConfiguration cnf = null; StreamReader sr = new StreamReader (configFileName); try { XmlReflectionImporter ri = new XmlReflectionImporter (); ri.AllowPrivateTypes = true; XmlSerializer ser = new XmlSerializer (ri.ImportTypeMapping (typeof (SerializationCodeGeneratorConfiguration))); cnf = (SerializationCodeGeneratorConfiguration) ser.Deserialize (sr); } finally { sr.Close (); } if (outputPath == null) outputPath = ""; CodeIdentifiers ids = new CodeIdentifiers (); if (cnf.Serializers != null) { foreach (SerializerInfo info in cnf.Serializers) { Type type; if (info.Assembly != null) { Assembly asm; try { asm = Assembly.Load (info.Assembly); } catch { asm = Assembly.LoadFrom (info.Assembly); } type = asm.GetType (info.ClassName, true); } else type = Type.GetType (info.ClassName); if (type == null) throw new InvalidOperationException ("Type " + info.ClassName + " not found"); string file = info.OutFileName; if (file == null || file.Length == 0) { int i = info.ClassName.LastIndexOf ("."); if (i != -1) file = info.ClassName.Substring (i+1); else file = info.ClassName; file = ids.AddUnique (file, type) + "Serializer.cs"; } StreamWriter writer = new StreamWriter (Path.Combine (outputPath, file)); try { XmlTypeMapping map; if (info.SerializationFormat == SerializationFormat.Literal) { XmlReflectionImporter ri = new XmlReflectionImporter (); map = ri.ImportTypeMapping (type); } else { SoapReflectionImporter ri = new SoapReflectionImporter (); map = ri.ImportTypeMapping (type); } SerializationCodeGenerator gen = new SerializationCodeGenerator (map, info); gen.GenerateSerializers (writer); } finally { writer.Close (); } } } } public void GenerateSerializers (TextWriter writer) { _writer = writer; _results = new GenerationResult [_xmlMaps.Length]; WriteLine ("// It is automatically generated"); WriteLine ("using System;"); WriteLine ("using System.Xml;"); WriteLine ("using System.Xml.Schema;"); WriteLine ("using System.Xml.Serialization;"); WriteLine ("using System.Text;"); WriteLine ("using System.Collections;"); WriteLine ("using System.Globalization;"); if (_config != null && _config.NamespaceImports != null && _config.NamespaceImports.Length > 0) { foreach (string ns in _config.NamespaceImports) WriteLine ("using " + ns + ";"); } WriteLine (""); string readerClassName = null; string writerClassName = null; string baseClassName = null; string implClassName = null; string namspace = null; if (_config != null) { readerClassName = _config.ReaderClassName; writerClassName = _config.WriterClassName; baseClassName = _config.BaseSerializerClassName; implClassName = _config.ImplementationClassName; namspace = _config.Namespace; } if (readerClassName == null || readerClassName.Length == 0) readerClassName = "GeneratedReader"; if (writerClassName == null || writerClassName.Length == 0) writerClassName = "GeneratedWriter"; if (baseClassName == null || baseClassName.Length == 0) baseClassName = "BaseXmlSerializer"; if (implClassName == null || implClassName.Length == 0) implClassName = "XmlSerializerContract"; readerClassName = GetUniqueClassName (readerClassName); writerClassName = GetUniqueClassName (writerClassName); baseClassName = GetUniqueClassName (baseClassName); implClassName = GetUniqueClassName (implClassName); Hashtable mapsByNamespace = new Hashtable (); Hashtable generatedMaps = new Hashtable (); for (int n=0; n<_xmlMaps.Length; n++) { _typeMap = _xmlMaps [n]; if (_typeMap == null) continue; _result = generatedMaps [_typeMap] as GenerationResult; if (_result != null) { _results[n] = _result; continue; } _result = new GenerationResult (); _results[n] = _result; generatedMaps [_typeMap] = _result; string typeName; if (_typeMap is XmlTypeMapping) typeName = CodeIdentifier.MakeValid (((XmlTypeMapping)_typeMap).TypeData.CSharpName); else typeName = ((XmlMembersMapping)_typeMap).ElementName; _result.ReaderClassName = readerClassName; _result.WriterClassName = writerClassName; _result.BaseSerializerClassName = baseClassName; _result.ImplementationClassName = implClassName; if (namspace == null || namspace.Length == 0) _result.Namespace = "Mono.GeneratedSerializers." + _typeMap.Format; else _result.Namespace = namspace; _result.WriteMethodName = GetUniqueName ("rwo", _typeMap, "WriteRoot_" + typeName); _result.ReadMethodName = GetUniqueName ("rro", _typeMap, "ReadRoot_" + typeName); _result.Mapping = _typeMap; ArrayList maps = (ArrayList) mapsByNamespace [_result.Namespace]; if (maps == null) { maps = new ArrayList (); mapsByNamespace [_result.Namespace] = maps; } maps.Add (_result); } foreach (DictionaryEntry entry in mapsByNamespace) { ArrayList maps = (ArrayList) entry.Value; WriteLine ("namespace " + entry.Key); WriteLineInd ("{"); if (_config == null || !_config.NoReader) GenerateReader (readerClassName, maps); WriteLine (""); if (_config == null || !_config.NoWriter) GenerateWriter (writerClassName, maps); WriteLine (""); GenerateContract (maps); WriteLineUni ("}"); WriteLine (""); } } public GenerationResult[] GenerationResults { get { return _results; } } public ArrayList ReferencedTypes { get { return _referencedTypes; } } void UpdateGeneratedTypes (ArrayList list) { for (int n=0; n 0) _writer.Write (','); _writer.Write ('"'); _writer.Write (emap.XmlNames[i]); _writer.Write ('\"'); } _writer.WriteLine (" };"); // create const long[] holding values of enum constants valuesArray = GetUniqueName ("gve", map, "_values" + map.XmlType); Write ("static readonly long[] " + valuesArray + " = { "); for (int i = 0; i < emap.Values.Length; i++) { if (i > 0) _writer.Write (','); _writer.Write (emap.Values[i].ToString (CultureInfo.InvariantCulture)); _writer.Write ("L"); } _writer.WriteLine (" };"); WriteLine (string.Empty); } WriteLine ("string " + GetGetEnumValueName (map) + " (" + GetTypeFullName (map.TypeData) + " val)"); WriteLineInd ("{"); WriteLineInd ("switch (val) {"); for (int i = 0; i < emap.EnumNames.Length; i++) WriteLine ("case " + map.TypeData.CSharpFullName + ".@" + emap.EnumNames[i] + ": return " + GetLiteral (emap.XmlNames[i]) + ";"); if (emap.IsFlags) { WriteLineInd ("default:"); // FromEnum actually covers this case too, but we save some cycles here WriteLine ("if (val.ToString () == \"0\") return string.Empty;"); Write ("return FromEnum ((long) val, " + xmlNamesArray + ", " + valuesArray); _writer.Write (", typeof ("); _writer.Write (map.TypeData.CSharpFullName); _writer.Write (").FullName"); _writer.Write (')'); // close FromEnum method call WriteUni (";"); // end statement } else { WriteLine ("default: throw CreateInvalidEnumValueException ((long) val, typeof (" + map.TypeData.CSharpFullName + ").FullName);"); } WriteLineUni ("}"); WriteLineUni ("}"); WriteLine (""); } void GenerateWriteObject (XmlTypeMapping typeMap) { WriteLine ("void " + GetWriteObjectName (typeMap) + " (" + GetTypeFullName (typeMap.TypeData) + " ob, string element, string namesp, bool isNullable, bool needType, bool writeWrappingElem)"); WriteLineInd ("{"); PushHookContext (); SetHookVar ("$TYPE", typeMap.TypeData.CSharpName); SetHookVar ("$FULLTYPE", typeMap.TypeData.CSharpFullName); SetHookVar ("$OBJECT", "ob"); SetHookVar ("$NULLABLE", "isNullable"); if (GenerateWriteHook (HookType.type, typeMap.TypeData.Type)) { WriteLineUni ("}"); WriteLine (""); PopHookContext (); return; } if (!typeMap.TypeData.IsValueType) { WriteLine ("if (((object)ob) == null)"); WriteLineInd ("{"); WriteLineInd ("if (isNullable)"); if (_format == SerializationFormat.Literal) WriteLine ("WriteNullTagLiteral(element, namesp);"); else WriteLine ("WriteNullTagEncoded (element, namesp);"); WriteLineUni ("return;"); WriteLineUni ("}"); WriteLine (""); } if (typeMap.TypeData.SchemaType == SchemaTypes.XmlNode) { if (_format == SerializationFormat.Literal) WriteLine ("WriteElementLiteral (ob, \"\", \"\", true, " + GetLiteral(typeMap.IsAny) + ");"); else WriteLine ("WriteElementEncoded (ob, \"\", \"\", true, " + GetLiteral(typeMap.IsAny) + ");"); GenerateEndHook (); WriteLineUni ("}"); WriteLine (""); PopHookContext (); return; } if (typeMap.TypeData.SchemaType == SchemaTypes.XmlSerializable) { WriteLine ("WriteSerializable (ob, element, namesp, isNullable, " + GetLiteral(!typeMap.IsAny) + ");"); GenerateEndHook (); WriteLineUni ("}"); WriteLine (""); PopHookContext (); return; } ArrayList types = typeMap.DerivedTypes; WriteLine ("System.Type type = ob.GetType ();"); WriteLine ("if (type == typeof(" + typeMap.TypeData.CSharpFullName + "))"); WriteLine ("{ }"); for (int n=0; n 1); if (map.ChoiceMember != null && container != null && index != null) { WriteLineInd ("if ((" + container + ".@" + map.ChoiceMember + " == null) || (" + index + " >= " + container + ".@" + map.ChoiceMember + ".Length))"); WriteLine ("throw CreateInvalidChoiceIdentifierValueException (" + container + ".GetType().ToString(), \"" + map.ChoiceMember + "\");"); Unindent (); } if (multichoice) WriteLine ("if (((object)" + item + ") == null) { }"); foreach (XmlTypeMapElementInfo info in map.ItemInfo) { if (map.ChoiceMember != null && multichoice) WriteLineInd ("else if (" + container + ".@" + map.ChoiceMember + "[" + index + "] == " + GetLiteral (info.ChoiceValue) + ") {"); else if (multichoice) WriteLineInd ("else if (" + item + ".GetType() == typeof(" + info.TypeData.CSharpFullName + ")) {"); if (targetString == null) GenerateWriteMemberElement (info, GetCast (info.TypeData, itemTypeData, item)); else { string strVal = GenerateGetStringValue (info.MappedType, info.TypeData, GetCast (info.TypeData, itemTypeData, item), false); WriteLine (targetString + ".Append (" + strVal + ").Append (\" \");"); } if (multichoice) WriteLineUni ("}"); } if (multichoice) WriteLine ("else throw CreateUnknownTypeException (" + item + ");"); } void GenerateWritePrimitiveValueLiteral (string memberValue, string name, string ns, XmlTypeMapping mappedType, TypeData typeData, bool wrapped, bool isNullable) { if (!wrapped) { string strVal = GenerateGetStringValue (mappedType, typeData, memberValue, false); WriteMetCall ("WriteValue", strVal); } else if (isNullable) { if (typeData.Type == typeof(XmlQualifiedName)) WriteMetCall ("WriteNullableQualifiedNameLiteral", GetLiteral(name), GetLiteral(ns), memberValue); else { string strVal = GenerateGetStringValue (mappedType, typeData, memberValue, true); WriteMetCall ("WriteNullableStringLiteral", GetLiteral(name), GetLiteral(ns), strVal); } } else { if (typeData.Type == typeof(XmlQualifiedName)) WriteMetCall ("WriteElementQualifiedName", GetLiteral(name), GetLiteral(ns), memberValue); else { string strVal = GenerateGetStringValue (mappedType, typeData, memberValue, false); WriteMetCall ("WriteElementString", GetLiteral(name),GetLiteral(ns), strVal); } } } void GenerateWritePrimitiveValueEncoded (string memberValue, string name, string ns, XmlQualifiedName xsiType, XmlTypeMapping mappedType, TypeData typeData, bool wrapped, bool isNullable) { if (!wrapped) { string strVal = GenerateGetStringValue (mappedType, typeData, memberValue, false); WriteMetCall ("WriteValue", strVal); } else if (isNullable) { if (typeData.Type == typeof(XmlQualifiedName)) WriteMetCall ("WriteNullableQualifiedNameEncoded", GetLiteral(name), GetLiteral(ns), memberValue, GetLiteral(xsiType)); else { string strVal = GenerateGetStringValue (mappedType, typeData, memberValue, true); WriteMetCall ("WriteNullableStringEncoded", GetLiteral(name), GetLiteral(ns), strVal, GetLiteral(xsiType)); } } else { if (typeData.Type == typeof(XmlQualifiedName)) WriteMetCall ("WriteElementQualifiedName", GetLiteral(name), GetLiteral(ns), memberValue, GetLiteral(xsiType)); else { string strVal = GenerateGetStringValue (mappedType, typeData, memberValue, false); WriteMetCall ("WriteElementString", GetLiteral(name),GetLiteral(ns), strVal, GetLiteral(xsiType)); } } } string GenerateGetMemberValue (XmlTypeMapMember member, string ob, bool isValueList) { if (isValueList) return GetCast (member.TypeData, TypeTranslator.GetTypeData (typeof(object)), ob + "[" + member.GlobalIndex + "]"); else return ob + ".@" + member.Name; } string GenerateMemberHasValueCondition (XmlTypeMapMember member, string ob, bool isValueList) { if (isValueList) { if (member.IsOptionalValueType) return ob + ".Length > " + Math.Max (member.GlobalIndex, member.SpecifiedGlobalIndex) + " && " + GetCast (typeof(bool), ob + "[" + member.SpecifiedGlobalIndex + "]"); else return ob + ".Length > " + member.GlobalIndex; } else if (member.DefaultValue != System.DBNull.Value) { string mem = ob + ".@" + member.Name; if (member.DefaultValue == null) return mem + " != null"; else if (member.TypeData.SchemaType == SchemaTypes.Enum) return mem + " != " + GetCast (member.TypeData, GetLiteral (member.DefaultValue)); else return mem + " != " + GetLiteral (member.DefaultValue); } else if (member.HasSpecified) { var sb = new StringBuilder (); sb.AppendFormat ("{0}.@{1}Specified", ob, member.Name); if (member.HasShouldSerialize) sb.AppendFormat (" && {0}.@ShouldSerialize{1} ()", ob, member.Name); return sb.ToString (); } else if (member.HasShouldSerialize) return ob + ".@ShouldSerialize" + member.Name + " ()"; return null; } void GenerateWriteInitCallbacks () { WriteLine ("protected override void InitCallbacks ()"); WriteLineInd ("{"); if (_format == SerializationFormat.Encoded) { foreach (XmlMapping xmap in _mapsToGenerate) { XmlTypeMapping map = xmap as XmlTypeMapping; if (map != null) WriteMetCall ("AddWriteCallback", GetTypeOf(map.TypeData), GetLiteral(map.XmlType), GetLiteral(map.Namespace), "new XmlSerializationWriteCallback (" + GetWriteObjectCallbackName (map) + ")"); } } WriteLineUni ("}"); WriteLine (""); if (_format == SerializationFormat.Encoded) { foreach (XmlTypeMapping xmap in _mapsToGenerate) { XmlTypeMapping map = xmap as XmlTypeMapping; if (map == null) continue; if (map.TypeData.SchemaType == SchemaTypes.Enum) WriteWriteEnumCallback (map); else WriteWriteObjectCallback (map); } } } void WriteWriteEnumCallback (XmlTypeMapping map) { WriteLine ("void " + GetWriteObjectCallbackName (map) + " (object ob)"); WriteLineInd ("{"); WriteMetCall (GetWriteObjectName(map), GetCast (map.TypeData, "ob"), GetLiteral(map.ElementName), GetLiteral(map.Namespace), "false", "true", "false"); WriteLineUni ("}"); WriteLine (""); } void WriteWriteObjectCallback (XmlTypeMapping map) { WriteLine ("void " + GetWriteObjectCallbackName (map) + " (object ob)"); WriteLineInd ("{"); WriteMetCall (GetWriteObjectName(map), GetCast (map.TypeData, "ob"), GetLiteral(map.ElementName), GetLiteral(map.Namespace), "false", "false", "false"); WriteLineUni ("}"); WriteLine (""); } #endregion #region Reader Generation //******************************************************* // Reader generation // public void GenerateReader (string readerClassName, ArrayList maps) { if (_config == null || !_config.GenerateAsInternal) WriteLine ("public class " + readerClassName + " : XmlSerializationReader"); else WriteLine ("internal class " + readerClassName + " : XmlSerializationReader"); WriteLineInd ("{"); // FromBinHexString() is not public, so use reflection here. WriteLine ("static readonly System.Reflection.MethodInfo fromBinHexStringMethod = typeof (XmlConvert).GetMethod (\"FromBinHexString\", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null, new Type [] {typeof (string)}, null);"); WriteLine ("static byte [] FromBinHexString (string input)"); WriteLineInd ("{"); WriteLine ("return input == null ? null : (byte []) fromBinHexStringMethod.Invoke (null, new object [] {input});"); WriteLineUni ("}"); _mapsToGenerate = new ArrayList (); _fixupCallbacks = new ArrayList (); InitHooks (); for (int n=0; n 0) readFlagsVars += ", "; readFlagsVars += readFlag[n] + "=false"; } n++; } if (readFlagsVars.Length > 0) { readFlagsVars = "bool " + readFlagsVars; WriteLine (readFlagsVars + ";"); } foreach (XmlTypeMapElementInfo info in map.AllElementInfos) if (info.ExplicitOrder >= 0) { WriteLine ("int idx = -1;"); break; } WriteLine (""); } string[] indexes = null; string[] flatLists = null; string[] flatListsChoices = null; if (map.FlatLists != null) { indexes = new string[map.FlatLists.Count]; flatLists = new string[map.FlatLists.Count]; string code = "int "; for (int n=0; n 0) code += ", "; code += indexes[n] + "=0"; if (!MemberHasReadReplaceHook (xmlMapType, mem)) { flatLists[n] = GetObTempVar (); string rval; WriteLine (mem.TypeData.CSharpFullName + " " + flatLists[n] + ";"); if (IsReadOnly (typeMap, mem, mem.TypeData, isValueList)) { rval = GenerateGetMemberValue (mem, ob, isValueList); WriteLine (flatLists[n] + " = " + rval + ";"); } else if (mem.TypeData.Type.IsArray) { rval = GenerateInitializeList (mem.TypeData); WriteLine (flatLists[n] + " = " + rval + ";"); } else { WriteLine (flatLists[n] + " = " + GenerateGetMemberValue (mem, ob, isValueList) + ";"); WriteLineInd ("if (((object)" + flatLists[n] + ") == null) {"); WriteLine (flatLists[n] + " = " + GenerateInitializeList (mem.TypeData) + ";"); GenerateSetMemberValue (mem, ob, flatLists[n], isValueList); WriteLineUni ("}"); } } if (mem.ChoiceMember != null) { if (flatListsChoices == null) flatListsChoices = new string [map.FlatLists.Count]; flatListsChoices[n] = GetObTempVar (); string rval = GenerateInitializeList (mem.ChoiceTypeData); WriteLine (mem.ChoiceTypeData.CSharpFullName + " " + flatListsChoices[n] + " = " + rval + ";"); } } WriteLine (code + ";"); WriteLine (""); } if (_format == SerializationFormat.Encoded && map.ElementMembers != null) { _fixupCallbacks.Add (xmlMap); WriteLine ("Fixup fixup = new Fixup(" + ob + ", new XmlSerializationFixupCallback(" + GetFixupCallbackName (xmlMap) + "), " + map.ElementMembers.Count + ");"); WriteLine ("AddFixup (fixup);"); WriteLine (""); } ArrayList infos = null; int maxInd; if (readBySoapOrder) { if (map.ElementMembers != null) maxInd = map.ElementMembers.Count; else maxInd = 0; } else { infos = new ArrayList (); infos.AddRange (map.AllElementInfos); maxInd = infos.Count; WriteLine ("while (Reader.NodeType != System.Xml.XmlNodeType.EndElement) "); WriteLineInd ("{"); WriteLine ("if (Reader.NodeType == System.Xml.XmlNodeType.Element) "); WriteLineInd ("{"); } first = true; for (int ind = 0; ind < maxInd; ind++) { XmlTypeMapElementInfo info = readBySoapOrder ? map.GetElement (ind) : (XmlTypeMapElementInfo) infos [ind]; if (!readBySoapOrder) { if (info.IsTextElement || info.IsUnnamedAnyElement) continue; string elemCond = first ? "" : "else "; elemCond += "if ("; if (info.ExplicitOrder >= 0) elemCond += "idx < " + info.ExplicitOrder + "&& "; if (!(info.Member.IsReturnValue && _format == SerializationFormat.Encoded)) { elemCond += "Reader.LocalName == " + GetLiteral (info.ElementName); if (!map.IgnoreMemberNamespace) elemCond += " && Reader.NamespaceURI == " + GetLiteral (info.Namespace); elemCond += " && "; } if (readFlag[info.Member.Index] != null) elemCond += "!" + readFlag[info.Member.Index] + ") {"; else elemCond += "true) {"; WriteLineInd (elemCond); } if (info.Member.GetType() == typeof (XmlTypeMapMemberList)) { if (_format == SerializationFormat.Encoded && info.MultiReferenceType) { string list = GetObTempVar (); WriteLine ("object " + list + " = ReadReferencingElement (out fixup.Ids[" + info.Member.Index + "]);"); RegisterReferencingMap (info.MappedType); WriteLineInd ("if (fixup.Ids[" + info.Member.Index + "] == null) {"); // Already read if (IsReadOnly (typeMap, info.Member, info.TypeData, isValueList)) WriteLine ("throw CreateReadOnlyCollectionException (" + GetLiteral(info.TypeData.CSharpFullName) + ");"); else GenerateSetMemberValue (info.Member, ob, GetCast (info.Member.TypeData,list), isValueList); WriteLineUni ("}"); if (!info.MappedType.TypeData.Type.IsArray) { WriteLineInd ("else {"); if (IsReadOnly (typeMap, info.Member, info.TypeData, isValueList)) WriteLine (list + " = " + GenerateGetMemberValue (info.Member, ob, isValueList) + ";"); else { WriteLine (list + " = " + GenerateCreateList (info.MappedType.TypeData.Type) + ";"); GenerateSetMemberValue (info.Member, ob, GetCast (info.Member.TypeData,list), isValueList); } WriteLine ("AddFixup (new CollectionFixup (" + list + ", new XmlSerializationCollectionFixupCallback (" + GetFillListName(info.Member.TypeData) + "), fixup.Ids[" + info.Member.Index + "]));"); WriteLine ("fixup.Ids[" + info.Member.Index + "] = null;"); // The member already has the value, no further fix needed. WriteLineUni ("}"); } } else { if (!GenerateReadMemberHook (xmlMapType, info.Member)) { if (IsReadOnly (typeMap, info.Member, info.TypeData, isValueList)) { GenerateReadListElement (info.MappedType, GenerateGetMemberValue (info.Member, ob, isValueList), GetLiteral(info.IsNullable), false); } else if (info.MappedType.TypeData.Type.IsArray) { if (info.IsNullable) GenerateSetMemberValue (info.Member, ob, GenerateReadListElement (info.MappedType, null, GetLiteral(info.IsNullable), true), isValueList); else { string list = GetObTempVar (); WriteLine (info.MappedType.TypeData.CSharpFullName + " " + list + " = " + GenerateReadListElement (info.MappedType, null, GetLiteral(info.IsNullable), true) + ";"); WriteLineInd ("if (((object)" + list + ") != null) {"); GenerateSetMemberValue (info.Member, ob, list, isValueList); WriteLineUni ("}"); } } else { string list = GetObTempVar (); WriteLine (info.MappedType.TypeData.CSharpFullName + " " + list + " = " + GenerateGetMemberValue (info.Member, ob, isValueList) + ";"); WriteLineInd ("if (((object)" + list + ") == null) {"); WriteLine (list + " = " + GenerateCreateList (info.MappedType.TypeData.Type) + ";"); GenerateSetMemberValue (info.Member, ob, list, isValueList); WriteLineUni ("}"); GenerateReadListElement (info.MappedType, list, GetLiteral(info.IsNullable), true); } GenerateEndHook (); } } if (!readBySoapOrder) WriteLine (readFlag[info.Member.Index] + " = true;"); } else if (info.Member.GetType() == typeof (XmlTypeMapMemberFlatList)) { XmlTypeMapMemberFlatList mem = (XmlTypeMapMemberFlatList)info.Member; if (!GenerateReadArrayMemberHook (xmlMapType, info.Member, indexes[mem.FlatArrayIndex])) { GenerateAddListValue (mem.TypeData, flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex], GenerateReadObjectElement (info), !IsReadOnly (typeMap, info.Member, info.TypeData, isValueList)); if (mem.ChoiceMember != null) { GenerateAddListValue (mem.ChoiceTypeData, flatListsChoices[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex], GetLiteral (info.ChoiceValue), true); } GenerateEndHook (); } WriteLine (indexes[mem.FlatArrayIndex] + "++;"); } else if (info.Member.GetType() == typeof (XmlTypeMapMemberAnyElement)) { XmlTypeMapMemberAnyElement mem = (XmlTypeMapMemberAnyElement)info.Member; if (mem.TypeData.IsListType) { if (!GenerateReadArrayMemberHook (xmlMapType, info.Member, indexes[mem.FlatArrayIndex])) { GenerateAddListValue (mem.TypeData, flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex], GetReadXmlNode (mem.TypeData.ListItemTypeData, false), true); GenerateEndHook (); } WriteLine (indexes[mem.FlatArrayIndex] + "++;"); } else { if (!GenerateReadMemberHook (xmlMapType, info.Member)) { GenerateSetMemberValue (mem, ob, GetReadXmlNode(mem.TypeData, false), isValueList); GenerateEndHook (); } } } else if (info.Member.GetType() == typeof(XmlTypeMapMemberElement)) { if (!readBySoapOrder) WriteLine (readFlag[info.Member.Index] + " = true;"); if (info.ExplicitOrder >= 0) WriteLine ("idx = " + info.ExplicitOrder + ";"); if (_format == SerializationFormat.Encoded) { string val = GetObTempVar (); RegisterReferencingMap (info.MappedType); if (info.Member.TypeData.SchemaType != SchemaTypes.Primitive) WriteLine ("object " + val + " = ReadReferencingElement (out fixup.Ids[" + info.Member.Index + "]);"); else WriteLine ("object " + val + " = ReadReferencingElement (" + GetLiteral(info.Member.TypeData.XmlType) + ", " + GetLiteral(System.Xml.Schema.XmlSchema.Namespace) + ", out fixup.Ids[" + info.Member.Index + "]);"); if (info.MultiReferenceType) WriteLineInd ("if (fixup.Ids[" + info.Member.Index + "] == null) {"); // already read else WriteLineInd ("if (" + val + " != null) {"); // null value GenerateSetMemberValue (info.Member, ob, GetCast (info.Member.TypeData,val), isValueList); WriteLineUni ("}"); } else if (!GenerateReadMemberHook (xmlMapType, info.Member)) { if (info.ChoiceValue != null) { XmlTypeMapMemberElement imem = (XmlTypeMapMemberElement) info.Member; WriteLine (ob + ".@" + imem.ChoiceMember + " = " + GetLiteral(info.ChoiceValue) + ";"); } GenerateSetMemberValue (info.Member, ob, GenerateReadObjectElement (info), isValueList); GenerateEndHook (); } } else throw new InvalidOperationException ("Unknown member type"); if (!readBySoapOrder) WriteLineUni ("}"); else WriteLine ("Reader.MoveToContent();"); first = false; } if (!readBySoapOrder) { if (!first) WriteLineInd ("else {"); if (map.DefaultAnyElementMember != null) { XmlTypeMapMemberAnyElement mem = map.DefaultAnyElementMember; if (mem.TypeData.IsListType) { if (!GenerateReadArrayMemberHook (xmlMapType, mem, indexes[mem.FlatArrayIndex])) { GenerateAddListValue (mem.TypeData, flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex], GetReadXmlNode(mem.TypeData.ListItemTypeData, false), true); GenerateEndHook (); } WriteLine (indexes[mem.FlatArrayIndex] + "++;"); } else if (! GenerateReadMemberHook (xmlMapType, mem)) { GenerateSetMemberValue (mem, ob, GetReadXmlNode(mem.TypeData, false), isValueList); GenerateEndHook (); } } else { if (!GenerateReadHook (HookType.unknownElement, xmlMapType)) { WriteLine ("UnknownNode (" + ob + ");"); GenerateEndHook (); } } if (!first) WriteLineUni ("}"); WriteLineUni ("}"); if (map.XmlTextCollector != null) { WriteLine ("else if (Reader.NodeType == System.Xml.XmlNodeType.Text || Reader.NodeType == System.Xml.XmlNodeType.CDATA)"); WriteLineInd ("{"); if (map.XmlTextCollector is XmlTypeMapMemberExpandable) { XmlTypeMapMemberExpandable mem = (XmlTypeMapMemberExpandable)map.XmlTextCollector; XmlTypeMapMemberFlatList flatl = mem as XmlTypeMapMemberFlatList; TypeData itype = (flatl == null) ? mem.TypeData.ListItemTypeData : flatl.ListMap.FindTextElement().TypeData; if (!GenerateReadArrayMemberHook (xmlMapType, map.XmlTextCollector, indexes[mem.FlatArrayIndex])) { string val = (itype.Type == typeof (string)) ? "Reader.ReadString()" : GetReadXmlNode (itype, false); GenerateAddListValue (mem.TypeData, flatLists[mem.FlatArrayIndex], indexes[mem.FlatArrayIndex], val, true); GenerateEndHook (); } WriteLine (indexes[mem.FlatArrayIndex] + "++;"); } else if (!GenerateReadMemberHook (xmlMapType, map.XmlTextCollector)) { XmlTypeMapMemberElement mem = (XmlTypeMapMemberElement) map.XmlTextCollector; XmlTypeMapElementInfo info = (XmlTypeMapElementInfo) mem.ElementInfo [0]; string str = GetStrTempVar (); WriteLine ("string " + str + " = Reader.ReadString();"); if (info.TypeData.Type == typeof (string)) GenerateSetMemberValue (mem, ob, str, isValueList); else { GenerateSetMemberValue (mem, ob, GenerateGetValueFromXmlString (str, info.TypeData, info.MappedType, info.IsNullable), isValueList); } GenerateEndHook (); } WriteLineUni ("}"); } WriteLine ("else"); WriteLine ("\tUnknownNode(" + ob + ");"); WriteLine (""); WriteLine ("Reader.MoveToContent();"); WriteLineUni ("}"); } else WriteLine ("Reader.MoveToContent();"); if (flatLists != null) { WriteLine (""); foreach (XmlTypeMapMemberExpandable mem in map.FlatLists) { if (MemberHasReadReplaceHook (xmlMapType, mem)) continue; string list = flatLists[mem.FlatArrayIndex]; if (mem.TypeData.Type.IsArray) WriteLine (list + " = (" + mem.TypeData.CSharpFullName + ") ShrinkArray (" + list + ", " + indexes[mem.FlatArrayIndex] + ", " + GetTypeOf(mem.TypeData.Type.GetElementType()) + ", true);"); if (!IsReadOnly (typeMap, mem, mem.TypeData, isValueList) && mem.TypeData.Type.IsArray) GenerateSetMemberValue (mem, ob, list, isValueList); } } if (flatListsChoices != null) { WriteLine (""); foreach (XmlTypeMapMemberExpandable mem in map.FlatLists) { if (MemberHasReadReplaceHook (xmlMapType, mem)) continue; if (mem.ChoiceMember == null) continue; string list = flatListsChoices[mem.FlatArrayIndex]; WriteLine (list + " = (" + mem.ChoiceTypeData.CSharpFullName + ") ShrinkArray (" + list + ", " + indexes[mem.FlatArrayIndex] + ", " + GetTypeOf(mem.ChoiceTypeData.Type.GetElementType()) + ", true);"); WriteLine (ob + ".@" + mem.ChoiceMember + " = " + list + ";"); } } GenerateSetListMembersDefaults (typeMap, map, ob, isValueList); GenerateEndHook (); } if (!isValueList) { WriteLine (""); WriteLine ("ReadEndElement();"); } } void GenerateReadAttributeMembers (XmlMapping xmlMap, ClassMap map, string ob, bool isValueList, ref bool first) { XmlTypeMapping typeMap = xmlMap as XmlTypeMapping; Type xmlMapType = (typeMap != null) ? typeMap.TypeData.Type : typeof(object[]); if (GenerateReadHook (HookType.attributes, xmlMapType)) return; XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember; if (anyAttrMember != null) { WriteLine ("int anyAttributeIndex = 0;"); WriteLine (anyAttrMember.TypeData.CSharpFullName + " anyAttributeArray = null;"); } WriteLine ("while (Reader.MoveToNextAttribute())"); WriteLineInd ("{"); first = true; if (map.AttributeMembers != null) { foreach (XmlTypeMapMemberAttribute at in map.AttributeMembers) { WriteLineInd ((first?"":"else ") + "if (Reader.LocalName == " + GetLiteral (at.AttributeName) + " && Reader.NamespaceURI == " + GetLiteral (at.Namespace) + ") {"); if (!GenerateReadMemberHook (xmlMapType, at)) { GenerateSetMemberValue (at, ob, GenerateGetValueFromXmlString ("Reader.Value", at.TypeData, at.MappedType, false), isValueList); GenerateEndHook (); } WriteLineUni ("}"); first = false; } } WriteLineInd ((first?"":"else ") + "if (IsXmlnsAttribute (Reader.Name)) {"); // If the map has NamespaceDeclarations, // then store this xmlns to the given member. // If the instance doesn't exist, then create. if (map.NamespaceDeclarations != null) { if (!GenerateReadMemberHook (xmlMapType, map.NamespaceDeclarations)) { string nss = ob + ".@" + map.NamespaceDeclarations.Name; WriteLine ("if (" + nss + " == null) " + nss + " = new XmlSerializerNamespaces ();"); WriteLineInd ("if (Reader.Prefix == \"xmlns\")"); WriteLine (nss + ".Add (Reader.LocalName, Reader.Value);"); Unindent (); WriteLineInd ("else"); WriteLine (nss + ".Add (\"\", Reader.Value);"); Unindent (); GenerateEndHook (); } } WriteLineUni ("}"); WriteLineInd ("else {"); if (anyAttrMember != null) { if (!GenerateReadArrayMemberHook (xmlMapType, anyAttrMember, "anyAttributeIndex")) { WriteLine ("System.Xml.XmlAttribute attr = (System.Xml.XmlAttribute) Document.ReadNode(Reader);"); if (typeof(System.Xml.Schema.XmlSchemaAnnotated).IsAssignableFrom (xmlMapType)) WriteLine ("ParseWsdlArrayType (attr);"); GenerateAddListValue (anyAttrMember.TypeData, "anyAttributeArray", "anyAttributeIndex", GetCast (anyAttrMember.TypeData.ListItemTypeData, "attr"), true); GenerateEndHook (); } WriteLine ("anyAttributeIndex++;"); } else { if (!GenerateReadHook (HookType.unknownAttribute, xmlMapType)) { WriteLine ("UnknownNode (" + ob + ");"); GenerateEndHook (); } } WriteLineUni ("}"); WriteLineUni ("}"); if (anyAttrMember != null && !MemberHasReadReplaceHook (xmlMapType, anyAttrMember)) { WriteLine (""); WriteLine("anyAttributeArray = (" + anyAttrMember.TypeData.CSharpFullName + ") ShrinkArray (anyAttributeArray, anyAttributeIndex, " + GetTypeOf(anyAttrMember.TypeData.Type.GetElementType()) + ", true);"); GenerateSetMemberValue (anyAttrMember, ob, "anyAttributeArray", isValueList); } WriteLine (""); WriteLine ("Reader.MoveToElement ();"); GenerateEndHook (); } void GenerateSetListMembersDefaults (XmlTypeMapping typeMap, ClassMap map, string ob, bool isValueList) { if (map.ListMembers != null) { ArrayList members = map.ListMembers; for (int n=0; n 0; } bool GenerateHook (HookType hookType, HookDir dir, Type type, string member) { GenerateHooks (hookType, dir, type, null, HookAction.InsertBefore); if (GenerateHooks (hookType, dir, type, null, HookAction.Replace)) { GenerateHooks (hookType, dir, type, null, HookAction.InsertAfter); return true; } else { HookInfo hi = new HookInfo (); hi.HookType = hookType; hi.Type = type; hi.Member = member; hi.Direction = dir; _hookOpenHooks.Push (hi); return false; } } void GenerateEndHook () { HookInfo hi = (HookInfo) _hookOpenHooks.Pop(); GenerateHooks (hi.HookType, hi.Direction, hi.Type, hi.Member, HookAction.InsertAfter); } bool GenerateHooks (HookType hookType, HookDir dir, Type type, string member, HookAction action) { if (_config == null) return false; ArrayList hooks = _config.GetHooks (hookType, dir, action, type, null); if (hooks.Count == 0) return false; foreach (Hook hook in hooks) { string code = hook.GetCode (action); foreach (DictionaryEntry de in _hookVariables) code = code.Replace ((string)de.Key, (string)de.Value); WriteMultilineCode (code); } return true; } string GetRootTypeName () { if (_typeMap is XmlTypeMapping) return GetTypeFullName (((XmlTypeMapping)_typeMap).TypeData); else return "object[]"; } string GetNumTempVar () { return "n" + (_tempVarId++); } string GetObTempVar () { return "o" + (_tempVarId++); } string GetStrTempVar () { return "s" + (_tempVarId++); } string GetBoolTempVar () { return "b" + (_tempVarId++); } string GetUniqueName (string uniqueGroup, object ob, string name) { name = CodeIdentifier.MakeValid (name.Replace ("[]","_array")); Hashtable names = (Hashtable) _uniqueNames [uniqueGroup]; if (names == null) { names = new Hashtable (); _uniqueNames [uniqueGroup] = names; } string res = (string) names [ob]; if (res != null) return res; foreach (string n in names.Values) if (n == name) return GetUniqueName (uniqueGroup, ob, name + (_methodId++)); names [ob] = name; return name; } void RegisterReferencingMap (XmlTypeMapping typeMap) { if (typeMap != null && !_mapsToGenerate.Contains (typeMap)) _mapsToGenerate.Add (typeMap); } string GetWriteObjectName (XmlTypeMapping typeMap) { if (!_mapsToGenerate.Contains (typeMap)) _mapsToGenerate.Add (typeMap); return GetUniqueName ("rw", typeMap, "WriteObject_" + typeMap.XmlType); } string GetReadObjectName (XmlTypeMapping typeMap) { if (!_mapsToGenerate.Contains (typeMap)) _mapsToGenerate.Add (typeMap); return GetUniqueName ("rr", typeMap, "ReadObject_" + typeMap.XmlType); } string GetGetEnumValueName (XmlTypeMapping typeMap) { if (!_mapsToGenerate.Contains (typeMap)) _mapsToGenerate.Add (typeMap); return GetUniqueName ("ge", typeMap, "GetEnumValue_" + typeMap.XmlType); } string GetWriteObjectCallbackName (XmlTypeMapping typeMap) { if (!_mapsToGenerate.Contains (typeMap)) _mapsToGenerate.Add (typeMap); return GetUniqueName ("wc", typeMap, "WriteCallback_" + typeMap.XmlType); } string GetFixupCallbackName (XmlMapping typeMap) { if (!_mapsToGenerate.Contains (typeMap)) _mapsToGenerate.Add (typeMap); if (typeMap is XmlTypeMapping) return GetUniqueName ("fc", typeMap, "FixupCallback_" + ((XmlTypeMapping)typeMap).XmlType); else return GetUniqueName ("fc", typeMap, "FixupCallback__Message"); } string GetUniqueClassName (string s) { return classNames.AddUnique (CodeIdentifier.MakeValid (s), null); } string GetReadObjectCall (XmlTypeMapping typeMap, string isNullable, string checkType) { if (_format == SerializationFormat.Literal) return GetReadObjectName (typeMap) + " (" + isNullable + ", " + checkType + ")"; else return GetCast (typeMap.TypeData, GetReadObjectName (typeMap) + " ()"); } string GetFillListName (TypeData td) { if (!_listsToFill.Contains (td)) _listsToFill.Add (td); return GetUniqueName ("fl", td, "Fill_" + CodeIdentifier.MakeValid (td.CSharpName)); } string GetCast (TypeData td, TypeData tdval, string val) { if (td.CSharpFullName == tdval.CSharpFullName) return val; else return GetCast (td, val); } string GetCast (TypeData td, string val) { return "((" + GetTypeFullName (td) + ") " + val + ")"; } string GetCast (Type td, string val) { return "((" + ToCSharpFullName (td) + ") " + val + ")"; } string GetTypeOf (TypeData td) { return "typeof(" + GetTypeFullName (td) + ")"; } string GetTypeOf (Type td) { return "typeof(" + ToCSharpFullName (td) + ")"; } string GetTypeFullName (TypeData td) { if (td.IsNullable && td.IsValueType) return td.CSharpFullName + "?"; return td.CSharpFullName; } string GetLiteral (object ob) { if (ob == null) return "null"; if (ob is string) return "\"" + ob.ToString().Replace("\"","\"\"") + "\""; if (ob is char) return (char) ob == '\'' ? "'\\''" : "'" + ob.ToString () + "'"; if (ob is DateTime) return "new DateTime (" + ((DateTime) ob).Ticks + ")"; if (ob is DateTimeOffset) return "new DateTimeOffset (" + ((DateTimeOffset) ob).Ticks + ")"; if (ob is TimeSpan) return "new TimeSpan (" + ((TimeSpan) ob).Ticks + ")"; if (ob is bool) return ((bool)ob) ? "true" : "false"; if (ob is XmlQualifiedName) { XmlQualifiedName qn = (XmlQualifiedName)ob; return "new XmlQualifiedName (" + GetLiteral(qn.Name) + "," + GetLiteral(qn.Namespace) + ")"; } if (ob is Enum) { string typeName = ToCSharpFullName (ob.GetType ()); StringBuilder sb = new StringBuilder (); string namedValue = Enum.Format (ob.GetType (), ob, "g"); string[] names = namedValue.Split (','); foreach (string name in names) { // individual named constants can be seperated by a comma // combined with some additional whitespace characters string cleanName = name.Trim (); if (cleanName.Length == 0) continue; if (sb.Length > 0) sb.Append (" | "); sb.Append (typeName); sb.Append ('.'); sb.Append (cleanName); } return sb.ToString (); } return (ob is IFormattable) ? ((IFormattable) ob).ToString (null, CultureInfo.InvariantCulture) : ob.ToString (); } void WriteLineInd (string code) { WriteLine (code); _indent++; } void WriteLineUni (string code) { if (_indent > 0) _indent--; WriteLine (code); } void Write (string code) { if (code.Length > 0) _writer.Write (new String ('\t', _indent)); _writer.Write (code); } void WriteUni (string code) { if (_indent > 0) _indent--; _writer.Write (code); _writer.WriteLine (string.Empty); } void WriteLine (string code) { if (code.Length > 0) _writer.Write (new String ('\t',_indent)); _writer.WriteLine (code); } void WriteMultilineCode (string code) { string tabs = new string ('\t',_indent); code = code.Replace ("\r",""); code = code.Replace ("\t",""); while (code.StartsWith ("\n")) code = code.Substring (1); while (code.EndsWith ("\n")) code = code.Substring (0, code.Length - 1); code = code.Replace ("\n", "\n" + tabs); WriteLine (code); } string Params (params string[] pars) { string res = ""; foreach (string p in pars) { if (res != "") res += ", "; res += p; } return res; } void WriteMetCall (string method, params string[] pars) { WriteLine (method + " (" + Params (pars) + ");"); } void Unindent () { _indent--; } #endregion } internal class GenerationResult { public XmlMapping Mapping; public string ReaderClassName; public string ReadMethodName; public string WriterClassName; public string WriteMethodName; public string Namespace; public string SerializerClassName; public string BaseSerializerClassName; public string ImplementationClassName; } }