679017453992082c8b5befede3bdab682f21a2a1
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Serialization / XmlReflectionImporter.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlReflectionImporter.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>                                                                
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml.Serialization {
9
10     using System.Reflection;
11     using System;
12     using System.Xml.Schema;
13     using System.Collections;
14     using System.ComponentModel;
15     using System.Globalization;
16     using System.CodeDom.Compiler;
17     using System.Threading;
18     using System.Diagnostics;
19
20     /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter"]/*' />
21     ///<internalonly/>
22     /// <devdoc>
23     ///    <para>[To be supplied.]</para>
24     /// </devdoc>
25     public class XmlReflectionImporter {
26         TypeScope typeScope;
27         XmlAttributeOverrides attributeOverrides;
28         XmlAttributes defaultAttributes = new XmlAttributes();
29         NameTable types = new NameTable();      // xmltypename + xmlns -> Mapping
30         NameTable nullables = new NameTable();  // xmltypename + xmlns -> NullableMapping
31         NameTable elements = new NameTable();   // xmlelementname + xmlns -> ElementAccessor
32         NameTable xsdAttributes;   // xmlattributetname + xmlns -> AttributeAccessor
33         Hashtable specials;   // type -> SpecialMapping
34         Hashtable anonymous = new Hashtable();   // type -> AnonymousMapping
35         NameTable serializables;  // type name --> new SerializableMapping
36         StructMapping root;
37         string defaultNs;
38         ModelScope modelScope;
39         int arrayNestingLevel;
40         XmlArrayItemAttributes savedArrayItemAttributes;
41         string savedArrayNamespace;
42         int choiceNum = 1;
43
44         enum ImportContext {
45             Text,
46             Attribute,
47             Element
48         }
49         
50         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter"]/*' />
51         /// <devdoc>
52         ///    <para>[To be supplied.]</para>
53         /// </devdoc>
54         public XmlReflectionImporter() : this(null, null) {
55         }
56
57         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter1"]/*' />
58         /// <devdoc>
59         ///    <para>[To be supplied.]</para>
60         /// </devdoc>
61         public XmlReflectionImporter(string defaultNamespace) : this(null, defaultNamespace) {
62         }
63
64         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter2"]/*' />
65         /// <devdoc>
66         ///    <para>[To be supplied.]</para>
67         /// </devdoc>
68         public XmlReflectionImporter(XmlAttributeOverrides attributeOverrides) : this(attributeOverrides, null) {
69         }
70
71         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.XmlReflectionImporter3"]/*' />
72         /// <devdoc>
73         ///    <para>[To be supplied.]</para>
74         /// </devdoc>
75         public XmlReflectionImporter(XmlAttributeOverrides attributeOverrides, string defaultNamespace) {
76             if (defaultNamespace == null)
77                 defaultNamespace = String.Empty;
78             if (attributeOverrides == null)
79                 attributeOverrides = new XmlAttributeOverrides();
80             this.attributeOverrides = attributeOverrides;
81             this.defaultNs = defaultNamespace;
82             this.typeScope = new TypeScope();
83             this.modelScope = new ModelScope(this.typeScope);
84         }
85
86         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.IncludeTypes"]/*' />
87         /// <devdoc>
88         ///    <para>[To be supplied.]</para>
89         /// </devdoc>
90         public void IncludeTypes(ICustomAttributeProvider provider) {
91             IncludeTypes(provider, new RecursionLimiter());
92         }
93
94         void IncludeTypes(ICustomAttributeProvider provider, RecursionLimiter limiter) {
95             object[] attrs = provider.GetCustomAttributes(typeof(XmlIncludeAttribute), false);
96             for (int i = 0; i < attrs.Length; i++) {
97                 Type type = ((XmlIncludeAttribute)attrs[i]).Type;
98                 IncludeType(type, limiter);
99             }
100         }
101
102         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.IncludeType"]/*' />
103         /// <devdoc>
104         ///    <para>[To be supplied.]</para>
105         /// </devdoc>
106         public void IncludeType(Type type) {
107             IncludeType(type, new RecursionLimiter());
108         }
109
110         void IncludeType(Type type, RecursionLimiter limiter) {
111             int previousNestingLevel = arrayNestingLevel;
112             XmlArrayItemAttributes previousArrayItemAttributes = savedArrayItemAttributes;
113             string previousArrayNamespace = savedArrayNamespace;
114             arrayNestingLevel = 0;
115             savedArrayItemAttributes = null;
116             savedArrayNamespace = null;
117            
118             TypeMapping mapping = ImportTypeMapping(modelScope.GetTypeModel(type), defaultNs, ImportContext.Element, string.Empty, null, limiter);
119             if (mapping.IsAnonymousType && !mapping.TypeDesc.IsSpecial) {
120                 //XmlAnonymousInclude=Cannot include anonymous type '{0}'.
121                 throw new InvalidOperationException(Res.GetString(Res.XmlAnonymousInclude, type.FullName));
122             }
123             arrayNestingLevel = previousNestingLevel;
124             savedArrayItemAttributes = previousArrayItemAttributes;
125             savedArrayNamespace = previousArrayNamespace;
126         }
127
128         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping"]/*' />
129         /// <devdoc>
130         ///    <para>[To be supplied.]</para>
131         /// </devdoc>
132         public XmlTypeMapping ImportTypeMapping(Type type) {
133             return ImportTypeMapping(type, null, null);
134         }
135
136         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping1"]/*' />
137         /// <devdoc>
138         ///    <para>[To be supplied.]</para>
139         /// </devdoc>
140         public XmlTypeMapping ImportTypeMapping(Type type, string defaultNamespace) {
141             return ImportTypeMapping(type, null, defaultNamespace);
142         }
143
144         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping2"]/*' />
145         /// <devdoc>
146         ///    <para>[To be supplied.]</para>
147         /// </devdoc>
148         public XmlTypeMapping ImportTypeMapping(Type type, XmlRootAttribute root) {
149             return ImportTypeMapping(type, root, null);
150         }
151
152         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportTypeMapping3"]/*' />
153         /// <devdoc>
154         ///    <para>[To be supplied.]</para>
155         /// </devdoc>
156         public XmlTypeMapping ImportTypeMapping(Type type, XmlRootAttribute root, string defaultNamespace) {
157             if (type == null)
158                 throw new ArgumentNullException("type");
159             XmlTypeMapping xmlMapping = new XmlTypeMapping(typeScope, ImportElement(modelScope.GetTypeModel(type), root, defaultNamespace, new RecursionLimiter()));
160             xmlMapping.SetKeyInternal(XmlMapping.GenerateKey(type, root, defaultNamespace));
161             xmlMapping.GenerateSerializer = true;
162             return xmlMapping;
163         }
164
165         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping"]/*' />
166         /// <devdoc>
167         ///    <para>[To be supplied.]</para>
168         /// </devdoc>
169         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement) {
170             return ImportMembersMapping(elementName, ns, members, hasWrapperElement, false);
171         }
172
173         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping1"]/*' />
174         /// <devdoc>
175         ///    <para>[To be supplied.]</para>
176         /// </devdoc>
177         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc) {
178             return ImportMembersMapping(elementName, ns, members, hasWrapperElement, rpc, false);
179         }
180
181         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping2"]/*' />
182         /// <devdoc>
183         ///    <para>[To be supplied.]</para>
184         /// </devdoc>
185         /// 
186         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool openModel) {
187             return ImportMembersMapping(elementName, ns, members, hasWrapperElement, rpc, openModel, XmlMappingAccess.Read | XmlMappingAccess.Write);
188         }
189
190         /// <include file='doc\XmlReflectionImporter.uex' path='docs/doc[@for="XmlReflectionImporter.ImportMembersMapping3"]/*' />
191         /// <devdoc>
192         ///    <para>[To be supplied.]</para>
193         /// </devdoc>
194         /// 
195         public XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool openModel, XmlMappingAccess access) {
196             ElementAccessor element = new ElementAccessor();
197             element.Name = elementName == null || elementName.Length == 0 ? elementName : XmlConvert.EncodeLocalName(elementName);
198             element.Namespace = ns;
199
200             MembersMapping membersMapping = ImportMembersMapping(members, ns, hasWrapperElement, rpc, openModel, new RecursionLimiter());
201             element.Mapping = membersMapping;
202             element.Form = XmlSchemaForm.Qualified;   // elements within soap:body are always qualified
203             if (!rpc) {
204                 if (hasWrapperElement)
205                     element = (ElementAccessor)ReconcileAccessor(element, this.elements);
206                 else {
207                     foreach (MemberMapping mapping in membersMapping.Members) {
208                         if (mapping.Elements != null && mapping.Elements.Length > 0) {
209                             mapping.Elements[0] = (ElementAccessor)ReconcileAccessor(mapping.Elements[0], this.elements);
210                         }
211                     }
212                 }
213             }
214             XmlMembersMapping xmlMapping = new XmlMembersMapping(typeScope, element, access);
215             xmlMapping.GenerateSerializer = true;
216             return xmlMapping;
217         }
218
219         XmlAttributes GetAttributes(Type type, bool canBeSimpleType) {
220             XmlAttributes attrs = attributeOverrides[type];
221             if (attrs != null) return attrs;
222             if (canBeSimpleType && TypeScope.IsKnownType(type)) {
223                 return defaultAttributes;
224             }
225             return new XmlAttributes(type);
226         }
227
228         XmlAttributes GetAttributes(MemberInfo memberInfo) {
229             XmlAttributes attrs = attributeOverrides[memberInfo.DeclaringType, memberInfo.Name];
230             if (attrs != null) return attrs;
231             return new XmlAttributes(memberInfo);
232         }
233
234         ElementAccessor ImportElement(TypeModel model, XmlRootAttribute root, string defaultNamespace, RecursionLimiter limiter) {
235             XmlAttributes a = GetAttributes(model.Type, true);
236
237             if (root == null)
238                 root = a.XmlRoot;
239             string ns = root == null ? null : root.Namespace;
240             if (ns == null) ns = defaultNamespace;
241             if (ns == null) ns = this.defaultNs;
242
243             arrayNestingLevel = -1;
244             savedArrayItemAttributes = null;
245             savedArrayNamespace = null;
246             ElementAccessor element = CreateElementAccessor(ImportTypeMapping(model, ns, ImportContext.Element, string.Empty, a, limiter), ns);
247
248             if (root != null) {
249                 if (root.ElementName.Length > 0)
250                     element.Name = XmlConvert.EncodeLocalName(root.ElementName);
251                 if (root.IsNullableSpecified && !root.IsNullable && model.TypeDesc.IsOptionalValue)
252                     //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
253                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, model.TypeDesc.BaseTypeDesc.FullName, "XmlRoot"));
254                 element.IsNullable = root.IsNullableSpecified ? root.IsNullable : model.TypeDesc.IsNullable || model.TypeDesc.IsOptionalValue;
255                 CheckNullable(element.IsNullable, model.TypeDesc, element.Mapping);
256             }
257             else
258                 element.IsNullable = model.TypeDesc.IsNullable || model.TypeDesc.IsOptionalValue;
259             element.Form = XmlSchemaForm.Qualified;
260             return (ElementAccessor)ReconcileAccessor(element, this.elements);
261         }
262
263         static string GetMappingName(Mapping mapping) {
264             if (mapping is MembersMapping)
265                 return "(method)";
266             else if (mapping is TypeMapping)
267                 return ((TypeMapping)mapping).TypeDesc.FullName;
268             else
269                 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
270         }
271         
272         ElementAccessor ReconcileLocalAccessor(ElementAccessor accessor, string ns) {
273             if (accessor.Namespace == ns) return accessor;
274             return (ElementAccessor)ReconcileAccessor(accessor, this.elements);
275         }
276
277         Accessor ReconcileAccessor(Accessor accessor, NameTable accessors) {
278             if (accessor.Any && accessor.Name.Length == 0)
279                  return accessor;
280
281             Accessor existing = (Accessor)accessors[accessor.Name, accessor.Namespace];
282             if (existing == null) {
283                 accessor.IsTopLevelInSchema = true;
284                 accessors.Add(accessor.Name, accessor.Namespace, accessor);
285                 return accessor;
286             }
287
288             if (existing.Mapping == accessor.Mapping) 
289                 return existing;
290
291             if (!(accessor.Mapping is MembersMapping) && !(existing.Mapping is MembersMapping)) {
292                 if (accessor.Mapping.TypeDesc == existing.Mapping.TypeDesc
293                     || (existing.Mapping is NullableMapping && accessor.Mapping.TypeDesc == ((NullableMapping)existing.Mapping).BaseMapping.TypeDesc)
294                     || (accessor.Mapping is NullableMapping && ((NullableMapping)accessor.Mapping).BaseMapping.TypeDesc == existing.Mapping.TypeDesc))
295                 {
296                     // need to compare default values
297                     string value1 = Convert.ToString(accessor.Default, CultureInfo.InvariantCulture);
298                     string value2 = Convert.ToString(existing.Default, CultureInfo.InvariantCulture);
299                     if (value1 == value2) {
300                         return existing;
301                     }
302                     throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessorDefault, accessor.Name, accessor.Namespace, value1, value2));
303                 }
304             }
305
306             if (accessor.Mapping is MembersMapping || existing.Mapping is MembersMapping)
307                 throw new InvalidOperationException(Res.GetString(Res.XmlMethodTypeNameConflict, accessor.Name, accessor.Namespace));
308
309             if (accessor.Mapping is ArrayMapping) {
310                 if (!(existing.Mapping is ArrayMapping)) {
311                     throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
312                 }
313                 ArrayMapping mapping = (ArrayMapping)accessor.Mapping;
314                 ArrayMapping existingMapping = mapping.IsAnonymousType ? null : (ArrayMapping)types[existing.Mapping.TypeName, existing.Mapping.Namespace];
315                 ArrayMapping first = existingMapping;
316                 while (existingMapping != null) {
317                     if (existingMapping == accessor.Mapping)
318                         return existing;
319                     existingMapping = existingMapping.Next;
320                 }
321                 mapping.Next = first;
322                 if (!mapping.IsAnonymousType)
323                     types[existing.Mapping.TypeName, existing.Mapping.Namespace] = mapping;
324                 return existing;
325             }
326             if (accessor is AttributeAccessor)
327                 throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAttributeAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
328             else
329                 throw new InvalidOperationException(Res.GetString(Res.XmlCannotReconcileAccessor, accessor.Name, accessor.Namespace, GetMappingName(existing.Mapping), GetMappingName(accessor.Mapping)));
330         }
331
332         Exception CreateReflectionException(string context, Exception e) {
333             return new InvalidOperationException(Res.GetString(Res.XmlReflectionError, context), e);
334         }
335
336         Exception CreateTypeReflectionException(string context, Exception e) {
337             return new InvalidOperationException(Res.GetString(Res.XmlTypeReflectionError, context), e);
338         }
339
340         Exception CreateMemberReflectionException(FieldModel model, Exception e) {
341             return new InvalidOperationException(Res.GetString(model.IsProperty ? Res.XmlPropertyReflectionError : Res.XmlFieldReflectionError, model.Name), e);
342         }
343
344         TypeMapping ImportTypeMapping(TypeModel model, string ns, ImportContext context, string dataType, XmlAttributes a, RecursionLimiter limiter) {
345             return ImportTypeMapping(model, ns, context, dataType, a, false, false, limiter);
346         }
347
348         TypeMapping ImportTypeMapping(TypeModel model, string ns, ImportContext context, string dataType, XmlAttributes a, bool repeats, bool openModel, RecursionLimiter limiter) {
349             try {
350                 if (dataType.Length > 0) {
351                     TypeDesc modelTypeDesc = TypeScope.IsOptionalValue(model.Type) ? model.TypeDesc.BaseTypeDesc : model.TypeDesc;
352                     if (!modelTypeDesc.IsPrimitive) {
353                         throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDataTypeUsage, dataType, "XmlElementAttribute.DataType"));
354                     }
355                     TypeDesc td = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
356                     if (td == null) {
357                         throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXsdDataType, dataType, "XmlElementAttribute.DataType", new XmlQualifiedName(dataType, XmlSchema.Namespace).ToString()));
358                     }
359                     if (modelTypeDesc.FullName != td.FullName) {
360                         throw new InvalidOperationException(Res.GetString(Res.XmlDataTypeMismatch, dataType, "XmlElementAttribute.DataType", modelTypeDesc.FullName));
361                     }
362                 }
363
364                 if (a == null)
365                     a = GetAttributes(model.Type, false);
366                 
367                 if ((a.XmlFlags & ~(XmlAttributeFlags.Type | XmlAttributeFlags.Root)) != 0)
368                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidTypeAttributes, model.Type.FullName));
369
370                 switch (model.TypeDesc.Kind) {
371                 case TypeKind.Enum: 
372                     return ImportEnumMapping((EnumModel)model, ns, repeats);
373                 case TypeKind.Primitive:
374                     if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
375                     return ImportPrimitiveMapping((PrimitiveModel)model, context, dataType, repeats);
376                 case TypeKind.Array:
377                 case TypeKind.Collection:
378                 case TypeKind.Enumerable:
379                     //if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
380                     if (context != ImportContext.Element) throw UnsupportedException(model.TypeDesc, context);
381                     arrayNestingLevel++;
382                     ArrayMapping arrayMapping = ImportArrayLikeMapping((ArrayModel)model, ns, limiter);
383                     arrayNestingLevel--;
384                     return arrayMapping;
385                 case TypeKind.Root:
386                 case TypeKind.Class:
387                 case TypeKind.Struct:
388                     if (context != ImportContext.Element) throw UnsupportedException(model.TypeDesc, context);
389                     if (model.TypeDesc.IsOptionalValue) {
390                         TypeDesc valueTypeDesc = string.IsNullOrEmpty(dataType) ? model.TypeDesc.BaseTypeDesc : typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
391                         string xsdTypeName = valueTypeDesc.DataType == null ? valueTypeDesc.Name : valueTypeDesc.DataType.Name;
392                         TypeMapping baseMapping = GetTypeMapping(xsdTypeName, ns, valueTypeDesc, types, null);
393                         if (baseMapping == null)
394                             baseMapping = ImportTypeMapping(modelScope.GetTypeModel(model.TypeDesc.BaseTypeDesc.Type), ns, context, dataType, null, repeats, openModel, limiter);
395                         return CreateNullableMapping(baseMapping, model.TypeDesc.Type);
396                     }
397                     else {
398                         return ImportStructLikeMapping((StructModel)model, ns, openModel, a, limiter);
399                     }
400                 default:
401                     if (model.TypeDesc.Kind == TypeKind.Serializable) {
402                         // We allow XmlRoot attribute on IXmlSerializable, but not others
403                         if ((a.XmlFlags & ~XmlAttributeFlags.Root) != 0) {
404                             throw new InvalidOperationException(Res.GetString(Res.XmlSerializableAttributes, model.TypeDesc.FullName, typeof(XmlSchemaProviderAttribute).Name));
405                         }
406                     }
407                     else {
408                         if (a.XmlFlags != 0) throw InvalidAttributeUseException(model.Type);
409                     }
410                     if (model.TypeDesc.IsSpecial)
411                         return ImportSpecialMapping(model.Type, model.TypeDesc, ns, context, limiter);
412                     throw UnsupportedException(model.TypeDesc, context);
413                 }
414             }
415             catch (Exception e) {
416                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
417                     throw;
418                 }
419                 throw CreateTypeReflectionException(model.TypeDesc.FullName, e);
420             }
421         }
422
423         internal static MethodInfo GetMethodFromSchemaProvider(XmlSchemaProviderAttribute provider, Type type) {
424             if (provider.IsAny) {
425                 // do not validate the schema provider method for wildcard types.
426                 return null;
427             }
428             else if (provider.MethodName == null) {
429                 throw new ArgumentNullException("MethodName");
430             }
431             if (!CodeGenerator.IsValidLanguageIndependentIdentifier(provider.MethodName))
432                 throw new ArgumentException(Res.GetString(Res.XmlGetSchemaMethodName, provider.MethodName), "MethodName");
433
434             MethodInfo getMethod = getMethod = type.GetMethod(provider.MethodName, /* BindingFlags.DeclaredOnly | */ BindingFlags.Static | BindingFlags.Public, null, new Type[] {typeof(XmlSchemaSet)}, null);
435             if (getMethod == null)
436                 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodMissing, provider.MethodName, typeof(XmlSchemaSet).Name, type.FullName));
437
438             if (!(typeof(XmlQualifiedName).IsAssignableFrom(getMethod.ReturnType)) && !(typeof(XmlSchemaType).IsAssignableFrom(getMethod.ReturnType)))
439                 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodReturnType, type.Name, provider.MethodName, typeof(XmlSchemaProviderAttribute).Name, typeof(XmlQualifiedName).FullName, typeof(XmlSchemaType).FullName));
440
441             return getMethod;
442         }
443        
444         SpecialMapping ImportSpecialMapping(Type type, TypeDesc typeDesc, string ns, ImportContext context, RecursionLimiter limiter) {
445             if (specials == null)
446                 specials = new Hashtable();
447             SpecialMapping mapping = (SpecialMapping)specials[type];
448             if (mapping != null) {
449                 CheckContext(mapping.TypeDesc, context);
450                 return mapping;
451             }
452             if (typeDesc.Kind == TypeKind.Serializable) {
453                 // 
454                 SerializableMapping serializableMapping = null;
455
456                 // get the schema method info
457                 object[] attrs = type.GetCustomAttributes(typeof(XmlSchemaProviderAttribute), false);
458
459                 if (attrs.Length > 0) {
460                     // new IXmlSerializable
461                     XmlSchemaProviderAttribute provider = (XmlSchemaProviderAttribute)attrs[0];
462                     MethodInfo method = GetMethodFromSchemaProvider(provider, type);
463                     serializableMapping = new SerializableMapping(method, provider.IsAny, ns);
464                     XmlQualifiedName qname = serializableMapping.XsiType;
465                     if (qname != null && !qname.IsEmpty) {
466                         if (serializables == null)
467                             serializables = new NameTable();
468                         SerializableMapping existingMapping = (SerializableMapping)serializables[qname];
469                         if (existingMapping != null) {
470                             if (existingMapping.Type == null) {
471                                 serializableMapping = existingMapping;
472                             }
473                             else if (existingMapping.Type != type) {
474                                 SerializableMapping next = existingMapping.Next;
475                                 existingMapping.Next = serializableMapping;
476                                 serializableMapping.Next = next;
477                             }
478                         }
479                         else {
480                             XmlSchemaType xsdType = serializableMapping.XsdType;
481                             if (xsdType != null)
482                                 SetBase(serializableMapping, xsdType.DerivedFrom);
483                             serializables[qname] = serializableMapping;
484                         }
485                         serializableMapping.TypeName = qname.Name;
486                         serializableMapping.Namespace = qname.Namespace;
487                     }
488                     serializableMapping.TypeDesc = typeDesc;
489                     serializableMapping.Type = type;
490                     IncludeTypes(type);
491                 }
492                 else {
493                     // old IXmlSerializable
494                     serializableMapping = new SerializableMapping();
495                     serializableMapping.TypeDesc = typeDesc;
496                     serializableMapping.Type = type;
497                 }
498                 mapping = serializableMapping;
499             }
500             else {
501                 mapping = new SpecialMapping();
502                 mapping.TypeDesc = typeDesc;
503             }
504             CheckContext(typeDesc, context);
505             specials.Add(type, mapping);
506             typeScope.AddTypeMapping(mapping);
507             return mapping;
508         }
509
510         internal static void ValidationCallbackWithErrorCode (object sender, ValidationEventArgs args) {
511             // 
512             if (args.Severity == XmlSeverityType.Error)
513                 throw new InvalidOperationException(Res.GetString(Res.XmlSerializableSchemaError, typeof(IXmlSerializable).Name, args.Message));
514         }
515
516         internal void SetBase(SerializableMapping mapping, XmlQualifiedName baseQname) {
517
518             if (baseQname.IsEmpty) return;
519             if (baseQname.Namespace == XmlSchema.Namespace) return;
520             XmlSchemaSet schemas = mapping.Schemas;
521             ArrayList srcSchemas = (ArrayList)schemas.Schemas(baseQname.Namespace);
522
523             if (srcSchemas.Count == 0) {
524                 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, baseQname.Namespace));
525             }
526             if (srcSchemas.Count > 1) {
527                 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaInclude, baseQname.Namespace, typeof(IXmlSerializable).Name, "GetSchema"));
528             }
529             XmlSchema s = (XmlSchema)srcSchemas[0];
530
531             XmlSchemaType t = (XmlSchemaType)s.SchemaTypes[baseQname];
532             t = t.Redefined != null ? t.Redefined : t;
533
534             if (serializables[baseQname] == null) {
535                 SerializableMapping baseMapping = new SerializableMapping(baseQname, schemas);
536                 SetBase(baseMapping, t.DerivedFrom);
537                 serializables.Add(baseQname, baseMapping);
538             }
539             mapping.SetBaseMapping((SerializableMapping)serializables[baseQname]);
540         }
541
542         static string GetContextName(ImportContext context) {
543             switch (context) {
544                 case ImportContext.Element: return "element";
545                 case ImportContext.Attribute: return "attribute";
546                 case ImportContext.Text: return "text";
547                 default:
548                     throw new ArgumentException(Res.GetString(Res.XmlInternalError), "context");
549             }
550         }
551
552         static Exception InvalidAttributeUseException(Type type) {
553             return new InvalidOperationException(Res.GetString(Res.XmlInvalidAttributeUse, type.FullName));
554         }
555
556         static Exception UnsupportedException(TypeDesc typeDesc, ImportContext context) {
557             return new InvalidOperationException(Res.GetString(Res.XmlIllegalTypeContext, typeDesc.FullName, GetContextName(context)));
558         }
559
560         StructMapping CreateRootMapping() {
561             TypeDesc typeDesc = typeScope.GetTypeDesc(typeof(object));
562             StructMapping mapping = new StructMapping();
563             mapping.TypeDesc = typeDesc;
564             mapping.TypeName = Soap.UrType;
565             mapping.Namespace = XmlSchema.Namespace;
566             mapping.Members = new MemberMapping[0];
567             mapping.IncludeInSchema = false;
568             return mapping;
569         }
570
571         NullableMapping CreateNullableMapping(TypeMapping baseMapping, Type type) {
572             TypeDesc typeDesc = baseMapping.TypeDesc.GetNullableTypeDesc(type);
573             TypeMapping existingMapping;
574             if (!baseMapping.IsAnonymousType)
575             {
576                 existingMapping = (TypeMapping)nullables[baseMapping.TypeName, baseMapping.Namespace];
577             }
578             else
579             {
580                 existingMapping = (TypeMapping)anonymous[type];
581             }
582
583             NullableMapping mapping;
584             if (existingMapping != null) {
585                 if (existingMapping is NullableMapping) {
586                     mapping = (NullableMapping)existingMapping;
587                     if (mapping.BaseMapping is PrimitiveMapping && baseMapping is PrimitiveMapping)
588                         return mapping;
589                     else if (mapping.BaseMapping == baseMapping) {
590                         return mapping;
591                     }
592                     else {
593                         throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
594                     }
595                 }
596                 else {
597                     throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, existingMapping.TypeDesc.FullName, typeDesc.Name, existingMapping.Namespace));
598                 }
599             }
600             mapping = new NullableMapping();
601             mapping.BaseMapping = baseMapping;
602             mapping.TypeDesc = typeDesc;
603             mapping.TypeName = baseMapping.TypeName;
604             mapping.Namespace = baseMapping.Namespace;
605             mapping.IncludeInSchema = baseMapping.IncludeInSchema;
606             if (!baseMapping.IsAnonymousType)
607             {
608             nullables.Add(baseMapping.TypeName, baseMapping.Namespace, mapping);
609             }
610             else
611             {
612                 anonymous[type] = mapping;
613             }
614             
615             typeScope.AddTypeMapping(mapping);
616             return mapping;
617         }
618
619         StructMapping GetRootMapping() {
620             if (root == null) {
621                 root = CreateRootMapping();
622                 typeScope.AddTypeMapping(root);
623             }
624             return root;
625         }
626
627         TypeMapping GetTypeMapping(string typeName, string ns, TypeDesc typeDesc, NameTable typeLib, Type type) {
628             TypeMapping mapping ;
629             if (typeName == null || typeName.Length == 0)
630                 mapping = type == null ? null : (TypeMapping)anonymous[type];
631             else
632                 mapping = (TypeMapping)typeLib[typeName, ns];
633
634             if (mapping == null) return null;
635             if (!mapping.IsAnonymousType && mapping.TypeDesc != typeDesc) 
636                 throw new InvalidOperationException(Res.GetString(Res.XmlTypesDuplicate, typeDesc.FullName, mapping.TypeDesc.FullName, typeName, ns));
637             return mapping;
638         }
639
640         StructMapping ImportStructLikeMapping(StructModel model, string ns, bool openModel, XmlAttributes a, RecursionLimiter limiter) {
641             if (model.TypeDesc.Kind == TypeKind.Root) return GetRootMapping();
642             if (a == null)
643                 a = GetAttributes(model.Type, false);
644
645             string typeNs = ns;
646             if (a.XmlType != null && a.XmlType.Namespace != null)
647                 typeNs = a.XmlType.Namespace;
648             else if (a.XmlRoot != null && a.XmlRoot.Namespace != null)
649                 typeNs = a.XmlRoot.Namespace;
650
651             string typeName = IsAnonymousType(a, ns) ? null : XsdTypeName(model.Type, a, model.TypeDesc.Name);
652             typeName = XmlConvert.EncodeLocalName(typeName);
653
654             StructMapping mapping = (StructMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc, types, model.Type);
655             if (mapping == null) {
656                 mapping = new StructMapping();
657                 mapping.TypeDesc = model.TypeDesc;
658                 mapping.Namespace = typeNs;
659                 mapping.TypeName = typeName;
660                 if (!mapping.IsAnonymousType)
661                     types.Add(typeName, typeNs, mapping);
662                 else
663                     anonymous[model.Type] = mapping;
664                 if (a.XmlType != null) {
665                     mapping.IncludeInSchema = a.XmlType.IncludeInSchema;
666                 }
667
668                 if (limiter.IsExceededLimit) {
669                     limiter.DeferredWorkItems.Add(new ImportStructWorkItem(model, mapping));
670                     return mapping;
671                 }
672
673                 limiter.Depth++;
674
675                 InitializeStructMembers(mapping, model, openModel, typeName, limiter);
676                 while (limiter.DeferredWorkItems.Count > 0) {
677                     int index = limiter.DeferredWorkItems.Count - 1;
678                     ImportStructWorkItem item = limiter.DeferredWorkItems[index];
679                     if (InitializeStructMembers(item.Mapping, item.Model, openModel, typeName, limiter)) {
680                         //
681                         // if InitializeStructMembers returns true, then there were *no* chages to the DeferredWorkItems
682                         //
683 #if DEBUG
684                     // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
685                     if (index != limiter.DeferredWorkItems.Count - 1)
686                         throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "DeferredWorkItems.Count have changed"));
687                     if (item != limiter.DeferredWorkItems[index])
688                         throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "DeferredWorkItems.Top have changed"));
689 #endif
690                         // Remove the last work item
691                         limiter.DeferredWorkItems.RemoveAt(index);
692                     }
693                 }
694                 limiter.Depth--;
695             }
696             return mapping;
697         }
698
699         bool InitializeStructMembers(StructMapping mapping, StructModel model, bool openModel, string typeName, RecursionLimiter limiter) {
700             if (mapping.IsFullyInitialized)
701                 return true;
702
703                 if (model.TypeDesc.BaseTypeDesc != null) {
704                     TypeModel baseModel = modelScope.GetTypeModel(model.Type.BaseType, false);
705                     if (!(baseModel is StructModel)) {
706                         //XmlUnsupportedInheritance=Using '{0}' as a base type for a class is not supported by XmlSerializer.
707                          throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedInheritance, model.Type.BaseType.FullName));
708                     }
709                 StructMapping baseMapping = ImportStructLikeMapping((StructModel)baseModel, mapping.Namespace, openModel, null, limiter);
710                 // check to see if the import of the baseMapping was deffered
711                 int baseIndex = limiter.DeferredWorkItems.IndexOf(baseMapping);
712                 if (baseIndex < 0) {
713                     mapping.BaseMapping = baseMapping;
714
715                     ICollection values = mapping.BaseMapping.LocalAttributes.Values;
716                     foreach (AttributeAccessor attribute in values) {
717                         AddUniqueAccessor(mapping.LocalAttributes, attribute);
718                     }
719                     if (!mapping.BaseMapping.HasExplicitSequence()) {
720                         values = mapping.BaseMapping.LocalElements.Values;
721                         foreach (ElementAccessor e in values) {
722                             AddUniqueAccessor(mapping.LocalElements, e);
723                         }
724                     }
725                 }
726                 else {
727                     // the import of the baseMapping was deffered, make sure that the derived mappings is deffered as well
728                     if (!limiter.DeferredWorkItems.Contains(mapping)) {
729                         limiter.DeferredWorkItems.Add(new ImportStructWorkItem(model, mapping));
730                     }
731                     // make sure that baseMapping get processed before the derived
732                     int top = limiter.DeferredWorkItems.Count - 1;
733                     if (baseIndex < top) {
734                         ImportStructWorkItem baseMappingWorkItem = limiter.DeferredWorkItems[baseIndex];
735                         limiter.DeferredWorkItems[baseIndex] = limiter.DeferredWorkItems[top];
736                         limiter.DeferredWorkItems[top] = baseMappingWorkItem;
737                     }
738                     return false;
739                 }
740             }
741                 ArrayList members = new ArrayList();
742                 TextAccessor textAccesor = null;
743                 bool hasElements = false;
744                 bool isSequence = false;
745                 
746                 foreach (MemberInfo memberInfo in model.GetMemberInfos()) {
747                     if ((memberInfo.MemberType & (MemberTypes.Field | MemberTypes.Property)) == 0)
748                         continue;
749                     XmlAttributes memberAttrs = GetAttributes(memberInfo);
750                     if (memberAttrs.XmlIgnore) continue;
751                     FieldModel fieldModel = model.GetFieldModel(memberInfo);
752                     if (fieldModel == null) continue;
753                     try {
754                     MemberMapping member = ImportFieldMapping(model, fieldModel, memberAttrs, mapping.Namespace, limiter);
755                         if (member == null) continue;
756                         if (mapping.BaseMapping != null) {
757                             if (mapping.BaseMapping.Declares(member, mapping.TypeName)) continue;
758                         }
759                         isSequence |= member.IsSequence;
760                         // add All memeber accessors to the scope accessors
761                         AddUniqueAccessor(member, mapping.LocalElements, mapping.LocalAttributes, isSequence);
762
763                         if (member.Text != null) {
764                             if (!member.Text.Mapping.TypeDesc.CanBeTextValue && member.Text.Mapping.IsList)
765                                 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalTypedTextAttribute, typeName, member.Text.Name, member.Text.Mapping.TypeDesc.FullName));
766                             if (textAccesor != null) {
767                                 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleText, model.Type.FullName));
768                             }
769                             textAccesor = member.Text;
770                         }
771                         if (member.Xmlns != null) {
772                             if (mapping.XmlnsMember != null)
773                                 throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlns, model.Type.FullName));
774                             mapping.XmlnsMember = member;
775                         }
776                         if (member.Elements != null && member.Elements.Length != 0) {
777                             hasElements = true;
778                         }
779                         members.Add(member);
780                     }
781                     catch (Exception e) {
782                         if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
783                             throw;
784                         }
785                         throw CreateMemberReflectionException(fieldModel, e);
786                     }
787                 }
788                 mapping.SetContentModel(textAccesor, hasElements);
789                 if (isSequence) {
790                     Hashtable ids = new Hashtable();
791                     for (int i = 0; i < members.Count; i++) {
792                         MemberMapping member = (MemberMapping)members[i];
793                         if (!member.IsParticle)
794                             continue;
795                         if (member.IsSequence) {
796                             if (ids[member.SequenceId] != null) {
797                                 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceUnique, member.SequenceId.ToString(CultureInfo.InvariantCulture), "Order", member.Name));
798                             }
799                             ids[member.SequenceId] = member;
800                         }
801                         else {
802                             throw new InvalidOperationException(Res.GetString(Res.XmlSequenceInconsistent, "Order", member.Name));
803                         }
804                     }
805                     members.Sort(new MemberMappingComparer());
806                 }
807                 mapping.Members = (MemberMapping[])members.ToArray(typeof(MemberMapping));
808
809                 if (mapping.BaseMapping == null) mapping.BaseMapping = GetRootMapping();
810
811                 if (mapping.XmlnsMember != null && mapping.BaseMapping.HasXmlnsMember)
812                     throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlns, model.Type.FullName));
813
814             IncludeTypes(model.Type, limiter);
815                 typeScope.AddTypeMapping(mapping);
816             if (openModel)
817                 mapping.IsOpenModel = true;
818             return true;
819         }
820
821         static bool IsAnonymousType(XmlAttributes a, string contextNs) {
822             if (a.XmlType != null && a.XmlType.AnonymousType) {
823                 //
824                 // check to see if the anonymous type is used in the original context
825                 // only treat it as Anonymous, if the referencing element's namespace
826                 // matches the original referencing element, otherwise revert to
827                 // non-Anonymous handling for backward compatibility.
828                 //
829                 string originalNs = a.XmlType.Namespace;
830                 return string.IsNullOrEmpty(originalNs) || originalNs == contextNs;
831             }
832             return false;
833         }
834
835         internal string XsdTypeName(Type type) {
836             if (type == typeof(object)) return Soap.UrType;
837             TypeDesc typeDesc = typeScope.GetTypeDesc(type);
838             if (typeDesc.IsPrimitive && typeDesc.DataType != null && typeDesc.DataType.Name != null && typeDesc.DataType.Name.Length > 0)
839                 return typeDesc.DataType.Name;
840             return XsdTypeName(type, GetAttributes(type, false), typeDesc.Name);
841         }
842
843         internal string XsdTypeName(Type type, XmlAttributes a, string name) {
844             string typeName = name;
845             if (a.XmlType != null && a.XmlType.TypeName.Length > 0)
846                 typeName = a.XmlType.TypeName;
847
848             if (type.IsGenericType && typeName.IndexOf('{') >= 0) {
849                 Type genType = type.GetGenericTypeDefinition();
850                 Type[] names = genType.GetGenericArguments();
851                 Type[] types = type.GetGenericArguments();
852
853                 for (int i = 0; i < names.Length; i++) {
854                     string argument = "{" + names[i] + "}";
855                     if (typeName.Contains(argument)) {
856                         typeName = typeName.Replace(argument, XsdTypeName(types[i]));
857                         if (typeName.IndexOf('{') < 0) {
858                             break;
859                         }
860                     }
861                 }
862             }
863             // 
864             return typeName;
865         }
866
867         private static int CountAtLevel(XmlArrayItemAttributes attributes, int level) {
868             int sum = 0;
869             for (int i = 0; i < attributes.Count; i++)
870                 if (attributes[i].NestingLevel == level) sum++;
871             return sum;
872         }
873
874         void SetArrayMappingType(ArrayMapping mapping, string defaultNs, Type type) {
875             XmlAttributes a = GetAttributes(type, false);
876             bool isAnonymous = IsAnonymousType(a, defaultNs);
877             if (isAnonymous) {
878                 mapping.TypeName = null;
879                 mapping.Namespace = defaultNs;
880                 return;
881             }
882             string name;
883             string ns;
884             TypeMapping itemTypeMapping;
885             ElementAccessor element = null;
886
887             if (mapping.Elements.Length == 1) {
888                 element = mapping.Elements[0];
889                 itemTypeMapping = element.Mapping;
890             }
891             else {
892                 itemTypeMapping = null;
893             }
894
895             bool generateTypeName = true;
896             if (a.XmlType != null) {
897                 ns = a.XmlType.Namespace;
898                 name = XsdTypeName(type, a, a.XmlType.TypeName);
899                 name = XmlConvert.EncodeLocalName(name);
900                 generateTypeName = name == null;
901             }
902             else if (itemTypeMapping is EnumMapping) {
903                 ns = itemTypeMapping.Namespace;
904                 name = itemTypeMapping.DefaultElementName;
905             }
906             else if (itemTypeMapping is PrimitiveMapping) {
907                 ns = defaultNs;
908                 name = itemTypeMapping.TypeDesc.DataType.Name;
909             }
910             else if (itemTypeMapping is StructMapping && itemTypeMapping.TypeDesc.IsRoot) {
911                 ns = defaultNs;
912                 name = Soap.UrType;
913             }
914             else if (itemTypeMapping != null) {
915                 ns = itemTypeMapping.Namespace == XmlSchema.Namespace ? defaultNs : itemTypeMapping.Namespace;
916                 name = itemTypeMapping.DefaultElementName;
917             }
918             else {
919                 ns = defaultNs;
920                 name = "Choice" + (choiceNum++);
921             }
922
923             if (name == null)
924                 name = "Any";
925
926             if (element != null)
927                 ns = element.Namespace;
928
929             if (ns == null)
930                 ns = defaultNs;
931
932             string uniqueName = name = generateTypeName ? "ArrayOf" + CodeIdentifier.MakePascal(name) : name;
933             int i = 1;
934             TypeMapping existingMapping = (TypeMapping)types[uniqueName, ns];
935             while (existingMapping != null) {
936                 if (existingMapping is ArrayMapping) {
937                     ArrayMapping arrayMapping = (ArrayMapping)existingMapping;
938                     if (AccessorMapping.ElementsMatch(arrayMapping.Elements, mapping.Elements)) {
939                         break;
940                     }
941                 }
942                 // need to re-name the mapping
943                 uniqueName = name + i.ToString(CultureInfo.InvariantCulture);
944                 existingMapping = (TypeMapping)types[uniqueName, ns];
945                 i++;
946             }
947             mapping.TypeName = uniqueName;
948             mapping.Namespace = ns;
949         }
950
951         ArrayMapping ImportArrayLikeMapping(ArrayModel model, string ns, RecursionLimiter limiter) {
952             ArrayMapping mapping = new ArrayMapping();
953             mapping.TypeDesc = model.TypeDesc;
954
955             if (savedArrayItemAttributes == null)
956                 savedArrayItemAttributes = new XmlArrayItemAttributes();
957             if (CountAtLevel(savedArrayItemAttributes, arrayNestingLevel) == 0)
958                 savedArrayItemAttributes.Add(CreateArrayItemAttribute(typeScope.GetTypeDesc(model.Element.Type), arrayNestingLevel));
959             CreateArrayElementsFromAttributes(mapping, savedArrayItemAttributes, model.Element.Type, savedArrayNamespace == null ? ns : savedArrayNamespace, limiter);
960             SetArrayMappingType(mapping, ns, model.Type);
961
962             // reconcile accessors now that we have the ArrayMapping namespace
963             for (int i = 0; i < mapping.Elements.Length; i++) {
964                 mapping.Elements[i] = ReconcileLocalAccessor(mapping.Elements[i], mapping.Namespace);
965             }
966
967             IncludeTypes(model.Type);
968
969             // in the case of an ArrayMapping we can have more that one mapping correspond to a type
970             // examples of that are ArrayList and object[] both will map tp ArrayOfur-type
971             // so we create a link list for all mappings of the same XSD type
972             ArrayMapping existingMapping = (ArrayMapping)types[mapping.TypeName, mapping.Namespace];
973             if (existingMapping != null) {
974                 ArrayMapping first = existingMapping;
975                 while (existingMapping != null) {
976                     if (existingMapping.TypeDesc == model.TypeDesc)
977                         return existingMapping;
978                     existingMapping = existingMapping.Next;
979                 }
980                 mapping.Next = first;
981                 if (!mapping.IsAnonymousType)
982                     types[mapping.TypeName, mapping.Namespace] = mapping;
983                 else
984                     anonymous[model.Type] = mapping;
985                 return mapping;
986             }
987             typeScope.AddTypeMapping(mapping);
988             if (!mapping.IsAnonymousType)
989                 types.Add(mapping.TypeName, mapping.Namespace, mapping);
990             else
991                 anonymous[model.Type] = mapping;
992             return mapping;
993         }
994
995         void CheckContext(TypeDesc typeDesc, ImportContext context) {
996             switch (context) {
997                 case ImportContext.Element:
998                     if (typeDesc.CanBeElementValue) return;
999                     break;
1000                 case ImportContext.Attribute:
1001                     if (typeDesc.CanBeAttributeValue) return;
1002                     break;
1003                 case ImportContext.Text:
1004                     if (typeDesc.CanBeTextValue || typeDesc.IsEnum || typeDesc.IsPrimitive)
1005                         return;
1006                     break;
1007                 default:
1008                     throw new ArgumentException(Res.GetString(Res.XmlInternalError), "context");
1009             }
1010             throw UnsupportedException(typeDesc, context);
1011         }
1012         
1013         PrimitiveMapping ImportPrimitiveMapping(PrimitiveModel model, ImportContext context, string dataType, bool repeats) {
1014             PrimitiveMapping mapping = new PrimitiveMapping();
1015             if (dataType.Length > 0) {
1016                 mapping.TypeDesc = typeScope.GetTypeDesc(dataType, XmlSchema.Namespace);
1017                 if (mapping.TypeDesc == null) {
1018                     // try it as a non-Xsd type
1019                     mapping.TypeDesc = typeScope.GetTypeDesc(dataType, UrtTypes.Namespace);
1020                     if (mapping.TypeDesc == null) {
1021                         throw new InvalidOperationException(Res.GetString(Res.XmlUdeclaredXsdType, dataType));
1022                     }
1023                 }
1024             }
1025             else {
1026                 mapping.TypeDesc = model.TypeDesc;
1027             }
1028             mapping.TypeName = mapping.TypeDesc.DataType.Name;
1029             mapping.Namespace = mapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : UrtTypes.Namespace;
1030             mapping.IsList = repeats;
1031             CheckContext(mapping.TypeDesc, context);
1032             return mapping;
1033         }
1034         
1035         EnumMapping ImportEnumMapping(EnumModel model, string ns, bool repeats) {
1036             XmlAttributes a = GetAttributes(model.Type, false);
1037             string typeNs = ns;
1038             if (a.XmlType != null && a.XmlType.Namespace != null)
1039                 typeNs = a.XmlType.Namespace;
1040
1041             string typeName = IsAnonymousType(a, ns) ? null : XsdTypeName(model.Type, a, model.TypeDesc.Name);
1042             typeName = XmlConvert.EncodeLocalName(typeName);
1043
1044             EnumMapping mapping = (EnumMapping)GetTypeMapping(typeName, typeNs, model.TypeDesc, types, model.Type);
1045             if (mapping == null) {
1046                 mapping = new EnumMapping();
1047                 mapping.TypeDesc = model.TypeDesc;
1048                 mapping.TypeName = typeName;
1049                 mapping.Namespace = typeNs;
1050                 mapping.IsFlags =  model.Type.IsDefined(typeof(FlagsAttribute), false);
1051                 if (mapping.IsFlags && repeats)
1052                     throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttributeFlagsArray, model.TypeDesc.FullName));
1053                 mapping.IsList = repeats;
1054                 mapping.IncludeInSchema = a.XmlType == null ? true : a.XmlType.IncludeInSchema;
1055                 if (!mapping.IsAnonymousType)
1056                     types.Add(typeName, typeNs, mapping);
1057                 else
1058                     anonymous[model.Type] = mapping;
1059                 ArrayList constants = new ArrayList();                
1060                 for (int i = 0; i < model.Constants.Length; i++) {
1061                     ConstantMapping constant = ImportConstantMapping(model.Constants[i]);
1062                     if (constant != null) constants.Add(constant);
1063                 }
1064                 if (constants.Count == 0) {
1065                     throw new InvalidOperationException(Res.GetString(Res.XmlNoSerializableMembers, model.TypeDesc.FullName));
1066                 }
1067                 mapping.Constants = (ConstantMapping[])constants.ToArray(typeof(ConstantMapping));
1068                 typeScope.AddTypeMapping(mapping);
1069             }
1070             return mapping;
1071         }
1072         
1073         ConstantMapping ImportConstantMapping(ConstantModel model) {
1074             XmlAttributes a = GetAttributes(model.FieldInfo);
1075             if (a.XmlIgnore) return null;
1076             if ((a.XmlFlags & ~XmlAttributeFlags.Enum) != 0)
1077                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidConstantAttribute));
1078             if (a.XmlEnum == null)
1079                 a.XmlEnum = new XmlEnumAttribute();
1080
1081             ConstantMapping constant = new ConstantMapping();
1082             constant.XmlName = a.XmlEnum.Name == null ? model.Name : a.XmlEnum.Name;
1083             constant.Name = model.Name;
1084             constant.Value = model.Value;
1085             return constant;
1086         }
1087         
1088         MembersMapping ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, string ns, bool hasWrapperElement, bool rpc, bool openModel, RecursionLimiter limiter) {
1089             MembersMapping members = new MembersMapping();
1090             members.TypeDesc = typeScope.GetTypeDesc(typeof(object[]));
1091             MemberMapping[] mappings = new MemberMapping[xmlReflectionMembers.Length];
1092             NameTable elements = new NameTable();
1093             NameTable attributes = new NameTable();
1094             TextAccessor textAccessor = null;
1095             bool isSequence = false;
1096
1097             for (int i = 0; i < mappings.Length; i++) {
1098                 try {
1099                     MemberMapping mapping = ImportMemberMapping(xmlReflectionMembers[i], ns, xmlReflectionMembers, rpc, openModel, limiter);
1100                     if (!hasWrapperElement) {
1101                         if (mapping.Attribute != null) {
1102                             if (rpc) {
1103                                 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributeAttributes));
1104                             }
1105                             else {
1106                                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidAttributeType, "XmlAttribute"));
1107                             }
1108                         }
1109                     }
1110                     if (rpc && xmlReflectionMembers[i].IsReturnValue) {
1111                         if (i > 0) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidReturnPosition));
1112                         mapping.IsReturnValue = true;
1113                     }
1114                     mappings[i] = mapping;
1115                     isSequence |= mapping.IsSequence;
1116                     if (!xmlReflectionMembers[i].XmlAttributes.XmlIgnore) {
1117                         // add All memeber accessors to the scope accessors
1118                         AddUniqueAccessor(mapping, elements, attributes, isSequence);
1119                     }
1120
1121                     mappings[i] = mapping;
1122                     if (mapping.Text != null) {
1123                         if (textAccessor != null) {
1124                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalMultipleTextMembers));
1125                         }
1126                         textAccessor = mapping.Text;
1127                     }
1128
1129                     if (mapping.Xmlns != null) {
1130                         if (members.XmlnsMember != null)
1131                             throw new InvalidOperationException(Res.GetString(Res.XmlMultipleXmlnsMembers));
1132                         members.XmlnsMember = mapping;
1133                     }
1134                 }
1135                 catch (Exception e) {
1136                     if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
1137                         throw;
1138                     }
1139                     throw CreateReflectionException(xmlReflectionMembers[i].MemberName, e);
1140                 }
1141             }
1142             if (isSequence) {
1143                 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMembers, "Order"));
1144             }
1145             members.Members = mappings;
1146             members.HasWrapperElement = hasWrapperElement;
1147             return members;
1148         }
1149
1150         MemberMapping ImportMemberMapping(XmlReflectionMember xmlReflectionMember, string ns, XmlReflectionMember[] xmlReflectionMembers, bool rpc, bool openModel, RecursionLimiter limiter) {
1151             XmlSchemaForm form = rpc ? XmlSchemaForm.Unqualified : XmlSchemaForm.Qualified;
1152             XmlAttributes a = xmlReflectionMember.XmlAttributes;
1153             TypeDesc typeDesc = typeScope.GetTypeDesc(xmlReflectionMember.MemberType);
1154
1155             if (a.XmlFlags == 0) {
1156                 if (typeDesc.IsArrayLike) {
1157                     XmlArrayAttribute xmlArray = CreateArrayAttribute(typeDesc);
1158                     xmlArray.ElementName = xmlReflectionMember.MemberName;
1159                     xmlArray.Namespace = rpc ? null : ns;
1160                     xmlArray.Form = form;
1161                     a.XmlArray = xmlArray;
1162                 }
1163                 else {
1164                     XmlElementAttribute xmlElement = CreateElementAttribute(typeDesc);
1165                     // If there is no metadata specified on a parameter, then see if someone used
1166                     // an XmlRoot attribute on the struct or class.
1167                     if (typeDesc.IsStructLike) {
1168                         XmlAttributes structAttrs = new XmlAttributes(xmlReflectionMember.MemberType);
1169                         if (structAttrs.XmlRoot != null) {
1170                             if (structAttrs.XmlRoot.ElementName.Length > 0)
1171                                 xmlElement.ElementName = structAttrs.XmlRoot.ElementName;
1172                             if (rpc) {
1173                                 xmlElement.Namespace = null;
1174                                 if (structAttrs.XmlRoot.IsNullableSpecified)
1175                                     xmlElement.IsNullable = structAttrs.XmlRoot.IsNullable;
1176                             }
1177                             else {
1178                                 xmlElement.Namespace = structAttrs.XmlRoot.Namespace;
1179                                 xmlElement.IsNullable = structAttrs.XmlRoot.IsNullable;
1180                             }
1181                         }
1182                     }
1183                     if (xmlElement.ElementName.Length == 0)
1184                         xmlElement.ElementName = xmlReflectionMember.MemberName;
1185                     if (xmlElement.Namespace == null && !rpc)
1186                         xmlElement.Namespace = ns;
1187                     xmlElement.Form = form;
1188                     a.XmlElements.Add(xmlElement);
1189                 }
1190             }
1191             else if (a.XmlRoot != null) {
1192                 CheckNullable(a.XmlRoot.IsNullable, typeDesc, null);
1193             }
1194             MemberMapping member = new MemberMapping();
1195             member.Name = xmlReflectionMember.MemberName;
1196             bool checkSpecified = FindSpecifiedMember(xmlReflectionMember.MemberName, xmlReflectionMembers) != null;
1197             FieldModel model = new FieldModel(xmlReflectionMember.MemberName, xmlReflectionMember.MemberType, typeScope.GetTypeDesc(xmlReflectionMember.MemberType), checkSpecified, false);
1198             member.CheckShouldPersist = model.CheckShouldPersist;
1199             member.CheckSpecified = model.CheckSpecified;
1200             member.ReadOnly = model.ReadOnly; // || !model.FieldTypeDesc.HasDefaultConstructor;
1201
1202             Type choiceIdentifierType = null;
1203             if (a.XmlChoiceIdentifier != null) {
1204                 choiceIdentifierType = GetChoiceIdentifierType(a.XmlChoiceIdentifier, xmlReflectionMembers, typeDesc.IsArrayLike, model.Name);
1205             }
1206             ImportAccessorMapping(member, model, a, ns, choiceIdentifierType, rpc, openModel, limiter);
1207             if (xmlReflectionMember.OverrideIsNullable && member.Elements.Length > 0)
1208                 member.Elements[0].IsNullable = false;
1209             return member;
1210         }
1211         
1212         internal static XmlReflectionMember FindSpecifiedMember(string memberName, XmlReflectionMember[] reflectionMembers) {
1213             for (int i = 0; i < reflectionMembers.Length; i++)
1214                 if (string.Compare(reflectionMembers[i].MemberName, memberName + "Specified", StringComparison.Ordinal) == 0)
1215                     return reflectionMembers[i];
1216             return null;
1217         }
1218
1219         MemberMapping ImportFieldMapping(StructModel parent, FieldModel model, XmlAttributes a, string ns, RecursionLimiter limiter) {
1220             MemberMapping member = new MemberMapping();
1221             member.Name = model.Name;
1222             member.CheckShouldPersist = model.CheckShouldPersist;
1223             member.CheckSpecified = model.CheckSpecified;
1224             member.MemberInfo = model.MemberInfo;
1225             member.CheckSpecifiedMemberInfo = model.CheckSpecifiedMemberInfo;
1226             member.CheckShouldPersistMethodInfo = model.CheckShouldPersistMethodInfo;
1227             member.ReadOnly = model.ReadOnly; // || !model.FieldTypeDesc.HasDefaultConstructor;
1228             Type choiceIdentifierType = null;
1229             if (a.XmlChoiceIdentifier != null) {
1230                 choiceIdentifierType = GetChoiceIdentifierType(a.XmlChoiceIdentifier, parent, model.FieldTypeDesc.IsArrayLike, model.Name);
1231             }
1232             ImportAccessorMapping(member, model, a, ns, choiceIdentifierType, false, false, limiter);
1233             return member;
1234         }
1235
1236         Type CheckChoiceIdentifierType(Type type, bool isArrayLike, string identifierName, string memberName) {
1237             if (type.IsArray) {
1238                 if (!isArrayLike) {
1239                     // Inconsistent type of the choice identifier '{0}'.  Please use {1}.
1240                     throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierType, identifierName, memberName, type.GetElementType().FullName));
1241                 }
1242                 type = type.GetElementType();
1243             }
1244             else if (isArrayLike) {
1245                 // Inconsistent type of the choice identifier '{0}'.  Please use {1}.
1246                 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierArrayType, identifierName, memberName, type.FullName));
1247             }
1248
1249             if (!type.IsEnum) {
1250                 // Choice identifier '{0}' must be an enum.
1251                 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentifierTypeEnum, identifierName));
1252             }
1253             return type;
1254         }
1255
1256         Type GetChoiceIdentifierType(XmlChoiceIdentifierAttribute choice, XmlReflectionMember[] xmlReflectionMembers, bool isArrayLike, string accessorName) {
1257             for (int i = 0; i < xmlReflectionMembers.Length; i++) {
1258                 if (choice.MemberName == xmlReflectionMembers[i].MemberName) {
1259                     return CheckChoiceIdentifierType(xmlReflectionMembers[i].MemberType, isArrayLike, choice.MemberName, accessorName);
1260                 }
1261             }
1262             // Missing '{0}' needed for serialization of choice '{1}'.
1263             throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName));
1264         }
1265
1266         Type GetChoiceIdentifierType(XmlChoiceIdentifierAttribute choice, StructModel structModel, bool isArrayLike, string accessorName) {
1267             // check that the choice field exists
1268
1269             MemberInfo[] infos = structModel.Type.GetMember(choice.MemberName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
1270             if (infos == null || infos.Length == 0) {
1271                 // if we can not find the choice identifier between fields, check proerties
1272                 PropertyInfo info = structModel.Type.GetProperty(choice.MemberName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
1273                 
1274                 if (info == null) {
1275                     // Missing '{0}' needed for serialization of choice '{1}'.
1276                     throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName));
1277                 }
1278                 infos = new MemberInfo[] { info };
1279             }
1280             else if (infos.Length > 1) {
1281                 // Ambiguous choice identifer: there are several members named '{0}'.
1282                 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferAmbiguous, choice.MemberName));
1283             }
1284
1285             FieldModel member = structModel.GetFieldModel(infos[0]);
1286             if (member == null) {
1287                 // Missing '{0}' needed for serialization of choice '{1}'.
1288                 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMemberMissing, choice.MemberName, accessorName));
1289             }
1290             choice.MemberInfo = member.MemberInfo;
1291             Type enumType = member.FieldType;
1292             enumType = CheckChoiceIdentifierType(enumType, isArrayLike, choice.MemberName, accessorName);
1293             return enumType;
1294         }
1295
1296         void CreateArrayElementsFromAttributes(ArrayMapping arrayMapping, XmlArrayItemAttributes attributes, Type arrayElementType, string arrayElementNs, RecursionLimiter limiter) {
1297             NameTable arrayItemElements = new NameTable();   // xmlelementname + xmlns -> ElementAccessor
1298
1299             for (int i = 0; attributes != null && i < attributes.Count; i++) {
1300                 XmlArrayItemAttribute xmlArrayItem = attributes[i];
1301                 if (xmlArrayItem.NestingLevel != arrayNestingLevel)
1302                     continue;
1303                 Type targetType = xmlArrayItem.Type != null ? xmlArrayItem.Type : arrayElementType;
1304                 TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1305                 ElementAccessor arrayItemElement = new ElementAccessor();
1306                 arrayItemElement.Namespace = xmlArrayItem.Namespace == null ? arrayElementNs : xmlArrayItem.Namespace;
1307                 arrayItemElement.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), arrayItemElement.Namespace, ImportContext.Element, xmlArrayItem.DataType, null, limiter);
1308                 arrayItemElement.Name = xmlArrayItem.ElementName.Length == 0 ? arrayItemElement.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlArrayItem.ElementName);
1309                 arrayItemElement.IsNullable = xmlArrayItem.IsNullableSpecified ? xmlArrayItem.IsNullable : targetTypeDesc.IsNullable || targetTypeDesc.IsOptionalValue;
1310                 arrayItemElement.Form = xmlArrayItem.Form == XmlSchemaForm.None ? XmlSchemaForm.Qualified : xmlArrayItem.Form;
1311                 CheckForm(arrayItemElement.Form, arrayElementNs != arrayItemElement.Namespace);
1312                 CheckNullable(arrayItemElement.IsNullable, targetTypeDesc, arrayItemElement.Mapping);
1313                 AddUniqueAccessor(arrayItemElements, arrayItemElement);
1314             }
1315             arrayMapping.Elements = (ElementAccessor[])arrayItemElements.ToArray(typeof(ElementAccessor));
1316         }
1317
1318         void ImportAccessorMapping(MemberMapping accessor, FieldModel model, XmlAttributes a, string ns, Type choiceIdentifierType, bool rpc, bool openModel, RecursionLimiter limiter) {
1319             XmlSchemaForm elementFormDefault = XmlSchemaForm.Qualified;
1320             int previousNestingLevel = arrayNestingLevel;
1321             int sequenceId = -1;
1322             XmlArrayItemAttributes previousArrayItemAttributes = savedArrayItemAttributes;
1323             string previousArrayNamespace = savedArrayNamespace;
1324             arrayNestingLevel = 0;
1325             savedArrayItemAttributes = null;
1326             savedArrayNamespace = null;
1327             Type accessorType = model.FieldType;
1328             string accessorName = model.Name;
1329             ArrayList elementList = new ArrayList();
1330             NameTable elements = new NameTable();
1331             accessor.TypeDesc = typeScope.GetTypeDesc(accessorType);
1332             XmlAttributeFlags flags = a.XmlFlags;
1333             accessor.Ignore = a.XmlIgnore;
1334             if (rpc)
1335                 CheckTopLevelAttributes(a, accessorName);
1336             else
1337                 CheckAmbiguousChoice(a, accessorType, accessorName);
1338
1339             XmlAttributeFlags elemFlags = XmlAttributeFlags.Elements | XmlAttributeFlags.Text | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier;
1340             XmlAttributeFlags attrFlags = XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyAttribute;
1341             XmlAttributeFlags arrayFlags = XmlAttributeFlags.Array | XmlAttributeFlags.ArrayItems;
1342
1343             // special case for byte[]. It can be a primitive (base64Binary or hexBinary), or it can
1344             // be an array of bytes. Our default is primitive; specify [XmlArray] to get array behavior.
1345             if ((flags & arrayFlags) != 0 && accessorType == typeof(byte[]))
1346                 accessor.TypeDesc = typeScope.GetArrayTypeDesc(accessorType);
1347
1348             if (a.XmlChoiceIdentifier != null) {
1349                 accessor.ChoiceIdentifier = new ChoiceIdentifierAccessor();
1350                 accessor.ChoiceIdentifier.MemberName = a.XmlChoiceIdentifier.MemberName;
1351                 accessor.ChoiceIdentifier.MemberInfo = a.XmlChoiceIdentifier.MemberInfo;
1352                 accessor.ChoiceIdentifier.Mapping = ImportTypeMapping(modelScope.GetTypeModel(choiceIdentifierType), ns, ImportContext.Element, String.Empty, null, limiter);
1353                 CheckChoiceIdentifierMapping((EnumMapping)accessor.ChoiceIdentifier.Mapping);
1354             }
1355
1356             if (accessor.TypeDesc.IsArrayLike) {
1357                 Type arrayElementType = TypeScope.GetArrayElementType(accessorType, model.FieldTypeDesc.FullName + "." + model.Name);
1358
1359                 if ((flags & attrFlags) != 0) {
1360                     if ((flags & attrFlags) != flags) 
1361                         throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttributesArrayAttribute));
1362
1363                     if (a.XmlAttribute != null && !accessor.TypeDesc.ArrayElementTypeDesc.IsPrimitive && !accessor.TypeDesc.ArrayElementTypeDesc.IsEnum) {
1364
1365                         if (accessor.TypeDesc.ArrayElementTypeDesc.Kind == TypeKind.Serializable) {
1366                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrTextInterface, accessorName, accessor.TypeDesc.ArrayElementTypeDesc.FullName, typeof(IXmlSerializable).Name));
1367                         }
1368                         else {
1369                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrText, accessorName, accessor.TypeDesc.ArrayElementTypeDesc.FullName));
1370                         }
1371                     }
1372
1373                     bool isList = a.XmlAttribute != null && (accessor.TypeDesc.ArrayElementTypeDesc.IsPrimitive || accessor.TypeDesc.ArrayElementTypeDesc.IsEnum);
1374
1375                     if (a.XmlAnyAttribute != null) {
1376                         a.XmlAttribute = new XmlAttributeAttribute();
1377                     }
1378
1379                     AttributeAccessor attribute = new AttributeAccessor();
1380                     Type targetType = a.XmlAttribute.Type == null ? arrayElementType : a.XmlAttribute.Type;
1381                     TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1382                     attribute.Name = Accessor.EscapeQName(a.XmlAttribute.AttributeName.Length == 0 ? accessorName : a.XmlAttribute.AttributeName);
1383                     attribute.Namespace = a.XmlAttribute.Namespace == null ? ns : a.XmlAttribute.Namespace;
1384                     attribute.Form = a.XmlAttribute.Form;
1385                     if (attribute.Form == XmlSchemaForm.None && ns != attribute.Namespace) {
1386                         attribute.Form = XmlSchemaForm.Qualified;
1387                     }
1388                     attribute.CheckSpecial();
1389                     CheckForm(attribute.Form, ns != attribute.Namespace);
1390                     attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), ns, ImportContext.Attribute, a.XmlAttribute.DataType, null, isList, false, limiter);
1391                     attribute.IsList = isList;
1392                     attribute.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1393                     attribute.Any = (a.XmlAnyAttribute != null);
1394                     if (attribute.Form == XmlSchemaForm.Qualified && attribute.Namespace != ns) {
1395                         if (xsdAttributes == null)
1396                             xsdAttributes = new NameTable();
1397                         attribute = (AttributeAccessor)ReconcileAccessor(attribute, xsdAttributes);
1398                     }
1399                     accessor.Attribute = attribute;
1400
1401                 }
1402                 else if ((flags & elemFlags) != 0) {
1403                     if ((flags & elemFlags) != flags)
1404                         throw new InvalidOperationException(Res.GetString(Res.XmlIllegalElementsArrayAttribute));
1405                     
1406                     if (a.XmlText != null) {
1407                         TextAccessor text = new TextAccessor();
1408                         Type targetType = a.XmlText.Type == null ? arrayElementType : a.XmlText.Type;
1409                         TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1410                         text.Name = accessorName; // unused except to make more helpful error messages
1411                         text.Mapping = ImportTypeMapping(modelScope.GetTypeModel(targetType), ns, ImportContext.Text, a.XmlText.DataType, null, true, false, limiter);
1412                         if (!(text.Mapping is SpecialMapping) && targetTypeDesc != typeScope.GetTypeDesc(typeof(string)))
1413                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayTextAttribute, accessorName));
1414
1415                         accessor.Text = text;
1416                     }
1417                     if (a.XmlText == null && a.XmlElements.Count == 0 && a.XmlAnyElements.Count == 0)
1418                         a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
1419                     
1420                     for (int i = 0; i < a.XmlElements.Count; i++) {
1421                         XmlElementAttribute xmlElement = a.XmlElements[i];
1422                         Type targetType = xmlElement.Type == null ? arrayElementType : xmlElement.Type;
1423                         TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1424                         TypeModel typeModel = modelScope.GetTypeModel(targetType);
1425                         ElementAccessor element = new ElementAccessor();
1426                         element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
1427                         element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, limiter);
1428                         if (a.XmlElements.Count == 1) {
1429                             element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
1430                             //element.IsUnbounded = element.Mapping is ArrayMapping;
1431                         }
1432                         else {
1433                             element.Name = xmlElement.ElementName.Length == 0 ? element.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlElement.ElementName);
1434                         }
1435                         element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1436                         if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
1437                             //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
1438                             throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
1439                         element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
1440                         element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
1441
1442                         CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1443                         if (!rpc) {
1444                             CheckForm(element.Form, ns != element.Namespace);
1445                             element = ReconcileLocalAccessor(element, ns);
1446                         }
1447                         if (xmlElement.Order != -1) {
1448                             if (xmlElement.Order != sequenceId &&  sequenceId != -1)
1449                                 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1450                             sequenceId = xmlElement.Order;
1451                         }
1452                         AddUniqueAccessor(elements, element);
1453                         elementList.Add(element);
1454                     }
1455                     NameTable anys = new NameTable();
1456                     for (int i = 0; i < a.XmlAnyElements.Count; i++) {
1457                         XmlAnyElementAttribute xmlAnyElement = a.XmlAnyElements[i];
1458                         Type targetType = typeof(IXmlSerializable).IsAssignableFrom(arrayElementType) ? arrayElementType : typeof(XmlNode).IsAssignableFrom(arrayElementType) ? arrayElementType : typeof(XmlElement);
1459                         if (!arrayElementType.IsAssignableFrom(targetType))
1460                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, arrayElementType.FullName));
1461                         string anyName = xmlAnyElement.Name.Length == 0 ? xmlAnyElement.Name : XmlConvert.EncodeLocalName(xmlAnyElement.Name);
1462                         string anyNs = xmlAnyElement.NamespaceSpecified ? xmlAnyElement.Namespace : null;
1463                         if (anys[anyName, anyNs] != null) {
1464                             // ignore duplicate anys
1465                             continue;
1466                         }
1467                         anys[anyName, anyNs] = xmlAnyElement;
1468                         if (elements[anyName, (anyNs == null ? ns : anyNs)] != null) {
1469                             throw new InvalidOperationException(Res.GetString(Res.XmlAnyElementDuplicate, accessorName, xmlAnyElement.Name, xmlAnyElement.Namespace == null ? "null" : xmlAnyElement.Namespace));
1470                         }
1471                         ElementAccessor element = new ElementAccessor();
1472                         element.Name = anyName;
1473                         element.Namespace = anyNs == null ? ns : anyNs;
1474                         element.Any = true;
1475                         element.AnyNamespaces = anyNs;
1476                         TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1477                         TypeModel typeModel = modelScope.GetTypeModel(targetType);
1478                         if (element.Name.Length > 0)
1479                             typeModel.TypeDesc.IsMixed = true;
1480                         element.Mapping = ImportTypeMapping(typeModel, element.Namespace, ImportContext.Element, String.Empty, null, limiter);
1481                         element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1482                         element.IsNullable = false;
1483                         element.Form = elementFormDefault;
1484
1485                         CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1486                         if (!rpc) {
1487                             CheckForm(element.Form, ns != element.Namespace);
1488                             element = ReconcileLocalAccessor(element, ns);
1489                         }
1490                         elements.Add(element.Name, element.Namespace, element);
1491                         elementList.Add(element);
1492                         if (xmlAnyElement.Order != -1) {
1493                             if (xmlAnyElement.Order != sequenceId &&  sequenceId != -1)
1494                                 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1495                             sequenceId = xmlAnyElement.Order;
1496                         }
1497                     }
1498                 }
1499                 else {
1500                     if ((flags & arrayFlags) != 0) {
1501                         if ((flags & arrayFlags) != flags)
1502                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalArrayArrayAttribute));
1503                     }
1504                     
1505                     TypeDesc arrayElementTypeDesc = typeScope.GetTypeDesc(arrayElementType);
1506                     if (a.XmlArray == null)
1507                         a.XmlArray = CreateArrayAttribute(accessor.TypeDesc);
1508                     if (CountAtLevel(a.XmlArrayItems, arrayNestingLevel) == 0)
1509                         a.XmlArrayItems.Add(CreateArrayItemAttribute(arrayElementTypeDesc, arrayNestingLevel));
1510                     ElementAccessor arrayElement = new ElementAccessor();
1511                     arrayElement.Name = XmlConvert.EncodeLocalName(a.XmlArray.ElementName.Length == 0 ? accessorName : a.XmlArray.ElementName);
1512                     arrayElement.Namespace = rpc ? null : a.XmlArray.Namespace == null ? ns : a.XmlArray.Namespace;
1513                     savedArrayItemAttributes = a.XmlArrayItems;
1514                     savedArrayNamespace = arrayElement.Namespace;
1515                     ArrayMapping arrayMapping = ImportArrayLikeMapping(modelScope.GetArrayModel(accessorType), ns, limiter);
1516                     arrayElement.Mapping = arrayMapping;
1517                     arrayElement.IsNullable = a.XmlArray.IsNullable;
1518                     arrayElement.Form = rpc ? XmlSchemaForm.Unqualified : a.XmlArray.Form == XmlSchemaForm.None ? elementFormDefault : a.XmlArray.Form;
1519                     sequenceId = a.XmlArray.Order;
1520                     CheckNullable(arrayElement.IsNullable, accessor.TypeDesc, arrayElement.Mapping);
1521                     if (!rpc) {
1522                         CheckForm(arrayElement.Form, ns != arrayElement.Namespace);
1523                         arrayElement = ReconcileLocalAccessor(arrayElement, ns);
1524                     }
1525                     savedArrayItemAttributes = null;
1526                     savedArrayNamespace = null;
1527                     
1528                     AddUniqueAccessor(elements, arrayElement);
1529                     elementList.Add(arrayElement);
1530                 }
1531             }
1532             else if (!accessor.TypeDesc.IsVoid) {
1533                 XmlAttributeFlags allFlags = XmlAttributeFlags.Elements | XmlAttributeFlags.Text | XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier | XmlAttributeFlags.XmlnsDeclarations;
1534                 if ((flags & allFlags) != flags)
1535                     throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttribute));
1536
1537                 if (accessor.TypeDesc.IsPrimitive || accessor.TypeDesc.IsEnum) {
1538                     if (a.XmlAnyElements.Count > 0) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, accessor.TypeDesc.FullName));
1539
1540                     if (a.XmlAttribute != null) {
1541                         if (a.XmlElements.Count > 0) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttribute));
1542                         if (a.XmlAttribute.Type != null) throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlAttribute"));
1543                         AttributeAccessor attribute = new AttributeAccessor();
1544                         attribute.Name = Accessor.EscapeQName(a.XmlAttribute.AttributeName.Length == 0 ? accessorName : a.XmlAttribute.AttributeName);
1545                         attribute.Namespace = a.XmlAttribute.Namespace == null ? ns : a.XmlAttribute.Namespace;
1546                         attribute.Form = a.XmlAttribute.Form;
1547                         if (attribute.Form == XmlSchemaForm.None && ns != attribute.Namespace) {
1548                             attribute.Form = XmlSchemaForm.Qualified;
1549                         }
1550                         attribute.CheckSpecial();
1551                         CheckForm(attribute.Form, ns != attribute.Namespace);
1552                         attribute.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), ns, ImportContext.Attribute, a.XmlAttribute.DataType, null, limiter);
1553                         attribute.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1554                         attribute.Any = a.XmlAnyAttribute != null;
1555                         if (attribute.Form == XmlSchemaForm.Qualified && attribute.Namespace != ns) {
1556                             if (xsdAttributes == null)
1557                                 xsdAttributes = new NameTable();
1558                             attribute = (AttributeAccessor)ReconcileAccessor(attribute, xsdAttributes);
1559                         }
1560                         accessor.Attribute = attribute;
1561                     }
1562                     else {
1563                         if (a.XmlText != null) {
1564                             if (a.XmlText.Type != null && a.XmlText.Type != accessorType) 
1565                                 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlText"));
1566                             TextAccessor text = new TextAccessor();
1567                             text.Name = accessorName; // unused except to make more helpful error messages
1568                             text.Mapping = ImportTypeMapping(modelScope.GetTypeModel(accessorType), ns, ImportContext.Text, a.XmlText.DataType, null, limiter);
1569                             accessor.Text = text;
1570                         }
1571                         else if (a.XmlElements.Count == 0) {
1572                             a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
1573                         }
1574
1575                         for (int i = 0; i < a.XmlElements.Count; i++) {
1576                             XmlElementAttribute xmlElement = a.XmlElements[i];
1577                             if (xmlElement.Type != null) {
1578                                 if (typeScope.GetTypeDesc(xmlElement.Type) != accessor.TypeDesc)
1579                                     throw new InvalidOperationException(Res.GetString(Res.XmlIllegalType, "XmlElement"));
1580                             }
1581                             ElementAccessor element = new ElementAccessor();
1582                             element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
1583                             element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
1584                             TypeModel typeModel = modelScope.GetTypeModel(accessorType);
1585                             element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, limiter);
1586                             if (element.Mapping.TypeDesc.Kind == TypeKind.Node) {
1587                                 element.Any = true;
1588                             }
1589                             element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1590                             if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
1591                                 //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
1592                                 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
1593                             element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
1594                             element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
1595
1596                             CheckNullable(element.IsNullable, accessor.TypeDesc, element.Mapping);
1597                             if (!rpc) {
1598                                 CheckForm(element.Form, ns != element.Namespace);
1599                                 element = ReconcileLocalAccessor(element, ns);
1600                             }
1601                             if (xmlElement.Order != -1) {
1602                                 if (xmlElement.Order != sequenceId &&  sequenceId != -1)
1603                                     throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1604                                 sequenceId = xmlElement.Order;
1605                             }
1606                             AddUniqueAccessor(elements, element);
1607                             elementList.Add(element);
1608                         }
1609                     }
1610                 }
1611                 else if (a.Xmlns) {
1612                     if (flags != XmlAttributeFlags.XmlnsDeclarations)
1613                         throw new InvalidOperationException(Res.GetString(Res.XmlSoleXmlnsAttribute));
1614                     
1615                     if (accessorType != typeof(XmlSerializerNamespaces)) {
1616                         throw new InvalidOperationException(Res.GetString(Res.XmlXmlnsInvalidType, accessorName, accessorType.FullName, typeof(XmlSerializerNamespaces).FullName));
1617                     }
1618                     accessor.Xmlns = new XmlnsAccessor();
1619                     accessor.Ignore = true;
1620                 }
1621                 else  {
1622                     if (a.XmlAttribute != null || a.XmlText != null) {
1623                         if (accessor.TypeDesc.Kind == TypeKind.Serializable) {
1624                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrTextInterface, accessorName, accessor.TypeDesc.FullName, typeof(IXmlSerializable).Name));
1625                         }
1626                         else {
1627                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAttrOrText, accessorName, accessor.TypeDesc));
1628                         }
1629                     }
1630                     if (a.XmlElements.Count == 0 && a.XmlAnyElements.Count == 0)
1631                         a.XmlElements.Add(CreateElementAttribute(accessor.TypeDesc));
1632                     for (int i = 0; i < a.XmlElements.Count; i++) {
1633                         XmlElementAttribute xmlElement = a.XmlElements[i];
1634                         Type targetType = xmlElement.Type == null ? accessorType : xmlElement.Type;
1635                         TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1636                         ElementAccessor element = new ElementAccessor();
1637                         TypeModel typeModel = modelScope.GetTypeModel(targetType);
1638                         element.Namespace = rpc ? null : xmlElement.Namespace == null ? ns : xmlElement.Namespace;
1639                         element.Mapping = ImportTypeMapping(typeModel, rpc ? ns : element.Namespace, ImportContext.Element, xmlElement.DataType, null, false, openModel, limiter);
1640                         if (a.XmlElements.Count == 1) {
1641                             element.Name = XmlConvert.EncodeLocalName(xmlElement.ElementName.Length == 0 ? accessorName : xmlElement.ElementName);
1642                         }
1643                         else {
1644                             element.Name = xmlElement.ElementName.Length == 0 ? element.Mapping.DefaultElementName : XmlConvert.EncodeLocalName(xmlElement.ElementName);
1645                         }
1646                         element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1647                         if (xmlElement.IsNullableSpecified && !xmlElement.IsNullable && typeModel.TypeDesc.IsOptionalValue)
1648                             //XmlInvalidNotNullable=IsNullable may not be set to 'false' for a Nullable<{0}> type. Consider using '{0}' type or removing the IsNullable property from the XmlElement attribute.
1649                             throw new InvalidOperationException(Res.GetString(Res.XmlInvalidNotNullable, typeModel.TypeDesc.BaseTypeDesc.FullName, "XmlElement"));
1650                         element.IsNullable = xmlElement.IsNullableSpecified ? xmlElement.IsNullable : typeModel.TypeDesc.IsOptionalValue;
1651                         element.Form = rpc ? XmlSchemaForm.Unqualified : xmlElement.Form == XmlSchemaForm.None ? elementFormDefault : xmlElement.Form;
1652                         CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1653
1654                         if (!rpc) {
1655                             CheckForm(element.Form, ns != element.Namespace);
1656                             element = ReconcileLocalAccessor(element, ns);
1657                         }
1658                         if (xmlElement.Order != -1) {
1659                             if (xmlElement.Order != sequenceId &&  sequenceId != -1)
1660                                 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1661                             sequenceId = xmlElement.Order;
1662                         }
1663                         AddUniqueAccessor(elements, element);
1664                         elementList.Add(element);
1665                     }
1666                     NameTable anys = new NameTable();
1667                     for (int i = 0; i < a.XmlAnyElements.Count; i++)
1668                     {
1669                         XmlAnyElementAttribute xmlAnyElement = a.XmlAnyElements[i];
1670                         Type targetType = typeof(IXmlSerializable).IsAssignableFrom(accessorType) ? accessorType : typeof(XmlNode).IsAssignableFrom(accessorType) ? accessorType : typeof(XmlElement);
1671                         if (!accessorType.IsAssignableFrom(targetType))
1672                             throw new InvalidOperationException(Res.GetString(Res.XmlIllegalAnyElement, accessorType.FullName));
1673
1674                         string anyName = xmlAnyElement.Name.Length == 0 ? xmlAnyElement.Name : XmlConvert.EncodeLocalName(xmlAnyElement.Name);
1675                         string anyNs = xmlAnyElement.NamespaceSpecified ? xmlAnyElement.Namespace : null;
1676                         if (anys[anyName, anyNs] != null)
1677                         {
1678                             // ignore duplicate anys
1679                             continue;
1680                         }
1681                         anys[anyName, anyNs] = xmlAnyElement;
1682                         if (elements[anyName, (anyNs == null ? ns : anyNs)] != null)
1683                         {
1684                             throw new InvalidOperationException(Res.GetString(Res.XmlAnyElementDuplicate, accessorName, xmlAnyElement.Name, xmlAnyElement.Namespace == null ? "null" : xmlAnyElement.Namespace));
1685                         }
1686                         ElementAccessor element = new ElementAccessor();
1687                         element.Name = anyName;
1688                         element.Namespace = anyNs == null ? ns : anyNs;
1689                         element.Any = true;
1690                         element.AnyNamespaces = anyNs;
1691                         TypeDesc targetTypeDesc = typeScope.GetTypeDesc(targetType);
1692                         TypeModel typeModel = modelScope.GetTypeModel(targetType);
1693
1694                         if (element.Name.Length > 0)
1695                             typeModel.TypeDesc.IsMixed = true;
1696                         element.Mapping = ImportTypeMapping(typeModel, element.Namespace, ImportContext.Element, String.Empty, null, false, openModel, limiter);
1697                         element.Default = GetDefaultValue(model.FieldTypeDesc, model.FieldType, a);
1698                         element.IsNullable = false;
1699                         element.Form = elementFormDefault;
1700                         CheckNullable(element.IsNullable, targetTypeDesc, element.Mapping);
1701                         if (!rpc) {
1702                             CheckForm(element.Form, ns != element.Namespace);
1703                             element = ReconcileLocalAccessor(element, ns);
1704                         }
1705                         if (xmlAnyElement.Order != -1) {
1706                             if (xmlAnyElement.Order != sequenceId &&  sequenceId != -1)
1707                                 throw new InvalidOperationException(Res.GetString(Res.XmlSequenceMatch, "Order"));
1708                             sequenceId = xmlAnyElement.Order;
1709                         }
1710                         elements.Add(element.Name, element.Namespace, element);
1711                         elementList.Add(element);
1712                     }
1713                 }
1714             }
1715             accessor.Elements = (ElementAccessor[])elementList.ToArray(typeof(ElementAccessor));
1716             accessor.SequenceId = sequenceId;
1717             
1718             if (rpc)
1719             {
1720                 if (accessor.TypeDesc.IsArrayLike && accessor.Elements.Length > 0 && !(accessor.Elements[0].Mapping is ArrayMapping))
1721                     throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitArrayElement, accessor.Elements[0].Name));
1722
1723                 if (accessor.Xmlns != null)
1724                     throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitXmlns, accessor.Name));
1725             }
1726
1727             if (accessor.ChoiceIdentifier != null) {
1728                 // find the enum value corresponding to each element
1729                 accessor.ChoiceIdentifier.MemberIds = new string[accessor.Elements.Length];
1730                 for (int i = 0; i < accessor.Elements.Length; i++) {
1731                     bool found = false;
1732                     ElementAccessor element = accessor.Elements[i];
1733                     EnumMapping choiceMapping = (EnumMapping)accessor.ChoiceIdentifier.Mapping;
1734                     for (int j = 0; j < choiceMapping.Constants.Length; j++) {
1735                         string xmlName = choiceMapping.Constants[j].XmlName;
1736
1737                         if (element.Any && element.Name.Length == 0) {
1738                             string anyNs = element.AnyNamespaces == null ? "##any" : element.AnyNamespaces;
1739                             if (xmlName.Substring(0, xmlName.Length-1) == anyNs) {
1740                                 accessor.ChoiceIdentifier.MemberIds[i] = choiceMapping.Constants[j].Name;
1741                                 found = true;
1742                                 break;
1743                             }
1744                             continue;
1745                         }
1746                         int colon = xmlName.LastIndexOf(':');
1747                         string choiceNs = colon < 0 ? choiceMapping.Namespace : xmlName.Substring(0, colon);
1748                         string choiceName = colon < 0 ? xmlName : xmlName.Substring(colon+1);
1749
1750                         if (element.Name == choiceName) {
1751                             if ((element.Form == XmlSchemaForm.Unqualified && string.IsNullOrEmpty(choiceNs)) || element.Namespace == choiceNs) {
1752                                 accessor.ChoiceIdentifier.MemberIds[i] = choiceMapping.Constants[j].Name;
1753                                 found = true;
1754                                 break;
1755                             }
1756                         }
1757                     }
1758                     if (!found) {
1759                         if (element.Any && element.Name.Length == 0) {
1760                             // Type {0} is missing enumeration value '##any' for XmlAnyElementAttribute.
1761                             throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingAnyValue, accessor.ChoiceIdentifier.Mapping.TypeDesc.FullName));
1762                         }
1763                         else {
1764                             string id = element.Namespace != null && element.Namespace.Length > 0 ? element.Namespace + ":" + element.Name : element.Name;
1765                             // Type {0} is missing value for '{1}'.
1766                             throw new InvalidOperationException(Res.GetString(Res.XmlChoiceMissingValue, accessor.ChoiceIdentifier.Mapping.TypeDesc.FullName, id, element.Name, element.Namespace));
1767                         }
1768                     }
1769                 }
1770             }
1771             arrayNestingLevel = previousNestingLevel;
1772             savedArrayItemAttributes = previousArrayItemAttributes;
1773             savedArrayNamespace = previousArrayNamespace;
1774         }
1775
1776         
1777         void CheckTopLevelAttributes(XmlAttributes a, string accessorName) {
1778             XmlAttributeFlags flags = a.XmlFlags;
1779
1780             if ((flags & (XmlAttributeFlags.Attribute | XmlAttributeFlags.AnyAttribute)) != 0) 
1781                 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributeAttributes));
1782
1783             if ((flags & (XmlAttributeFlags.Text | XmlAttributeFlags.AnyElements | XmlAttributeFlags.ChoiceIdentifier)) != 0) 
1784                 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitAttributes));
1785
1786             if (a.XmlElements != null && a.XmlElements.Count > 0) {
1787                 if (a.XmlElements.Count > 1) {
1788                     throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElements));
1789                 }
1790                 XmlElementAttribute xmlElement = a.XmlElements[0];
1791                 if (xmlElement.Namespace != null) {
1792                     throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNamespace, "Namespace", xmlElement.Namespace));
1793                 }
1794                 if (xmlElement.IsNullable) {
1795                     throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNullable, "IsNullable", "true"));
1796                 }
1797             }
1798             if (a.XmlArray != null && a.XmlArray.Namespace != null) {
1799                 throw new InvalidOperationException(Res.GetString(Res.XmlRpcLitElementNamespace, "Namespace", a.XmlArray.Namespace));
1800             }
1801         }
1802
1803         void CheckAmbiguousChoice(XmlAttributes a, Type accessorType, string accessorName) {
1804             Hashtable choiceTypes = new Hashtable();
1805
1806             XmlElementAttributes elements = a.XmlElements;
1807             if (elements != null && elements.Count >= 2 && a.XmlChoiceIdentifier == null) {
1808                 for (int i = 0; i < elements.Count; i++) {
1809                     Type type = elements[i].Type == null ? accessorType : elements[i].Type;
1810                     if (choiceTypes.Contains(type)) {
1811                         // You need to add {0} to the '{1}'.
1812                         throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMissing, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
1813                     }
1814                     else {
1815                         choiceTypes.Add(type, false);
1816                     }
1817                 }
1818             }
1819             if (choiceTypes.Contains(typeof(XmlElement)) && a.XmlAnyElements.Count > 0) {
1820                 // You need to add {0} to the '{1}'.
1821                 throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdentiferMissing, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
1822             }
1823
1824             XmlArrayItemAttributes items = a.XmlArrayItems;
1825             if (items != null && items.Count >= 2) {
1826                 NameTable arrayTypes = new NameTable();
1827
1828                 for (int i = 0; i < items.Count; i++) {
1829                     Type type = items[i].Type == null ? accessorType : items[i].Type;
1830                     string ns = items[i].NestingLevel.ToString(CultureInfo.InvariantCulture);
1831                     XmlArrayItemAttribute item = (XmlArrayItemAttribute)arrayTypes[type.FullName, ns];
1832                     if (item != null) {
1833                         throw new InvalidOperationException(Res.GetString(Res.XmlArrayItemAmbiguousTypes, accessorName, item.ElementName, items[i].ElementName, typeof(XmlElementAttribute).Name, typeof(XmlChoiceIdentifierAttribute).Name, accessorName));
1834                     }
1835                     else {
1836                         arrayTypes[type.FullName, ns] =  items[i];
1837                     }
1838                 }
1839             }
1840         }
1841
1842         void CheckChoiceIdentifierMapping(EnumMapping choiceMapping) {
1843             NameTable ids = new NameTable();
1844             for (int i = 0; i < choiceMapping.Constants.Length; i++) {
1845                 string choiceId = choiceMapping.Constants[i].XmlName;
1846                 int colon = choiceId.LastIndexOf(':');
1847                 string choiceName = colon < 0 ? choiceId : choiceId.Substring(colon+1);
1848                 string choiceNs = colon < 0 ? "" : choiceId.Substring(0, colon);
1849
1850                 if (ids[choiceName, choiceNs] != null) {
1851                     // Enum values in the XmlChoiceIdentifier '{0}' have to be unique.  Value '{1}' already present.
1852                     throw new InvalidOperationException(Res.GetString(Res.XmlChoiceIdDuplicate, choiceMapping.TypeName, choiceId));
1853                 }
1854                 ids.Add(choiceName, choiceNs, choiceMapping.Constants[i]);
1855             }
1856         }
1857
1858         object GetDefaultValue(TypeDesc fieldTypeDesc, Type t, XmlAttributes a) {
1859             if (a.XmlDefaultValue == null || a.XmlDefaultValue == DBNull.Value) return null;
1860             if (!(fieldTypeDesc.Kind == TypeKind.Primitive || fieldTypeDesc.Kind == TypeKind.Enum))  {
1861                 //throw new InvalidOperationException(Res.GetString(Res.XmlIllegalDefault));
1862                 a.XmlDefaultValue = null;
1863                 return a.XmlDefaultValue;
1864             }
1865             // for enums validate and return a string representation
1866             if (fieldTypeDesc.Kind == TypeKind.Enum) {
1867                 string strValue = Enum.Format(t, a.XmlDefaultValue, "G").Replace(",", " ");
1868                 string numValue = Enum.Format(t, a.XmlDefaultValue, "D");
1869                 if (strValue == numValue) // means enum value wasn't recognized
1870                     throw new InvalidOperationException(Res.GetString(Res.XmlInvalidDefaultValue, strValue, a.XmlDefaultValue.GetType().FullName));
1871                 return strValue;
1872             }
1873             return a.XmlDefaultValue;
1874         }
1875
1876         static XmlArrayItemAttribute CreateArrayItemAttribute(TypeDesc typeDesc, int nestingLevel) {
1877             XmlArrayItemAttribute xmlArrayItem = new XmlArrayItemAttribute();
1878             xmlArrayItem.NestingLevel = nestingLevel;
1879             return xmlArrayItem;
1880         }
1881
1882         static XmlArrayAttribute CreateArrayAttribute(TypeDesc typeDesc) {
1883             XmlArrayAttribute xmlArrayItem = new XmlArrayAttribute();
1884             return xmlArrayItem;
1885         }
1886
1887         static XmlElementAttribute CreateElementAttribute(TypeDesc typeDesc) {
1888             XmlElementAttribute xmlElement = new XmlElementAttribute();
1889             xmlElement.IsNullable = typeDesc.IsOptionalValue;
1890             return xmlElement;
1891         }
1892
1893         static void AddUniqueAccessor(INameScope scope, Accessor accessor) {
1894             Accessor existing = (Accessor)scope[accessor.Name, accessor.Namespace];
1895             if (existing != null) {
1896                 if (accessor is ElementAccessor) {
1897                     throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateElementName, existing.Name, existing.Namespace));
1898                 }
1899                 else {
1900                     #if DEBUG
1901                     if (!(accessor is AttributeAccessor))
1902                         throw new InvalidOperationException(Res.GetString(Res.XmlInternalErrorDetails, "Bad accessor type " + accessor.GetType().FullName));
1903                     #endif
1904                     throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateAttributeName, existing.Name, existing.Namespace));
1905                 }
1906             }
1907             else {
1908                 scope[accessor.Name, accessor.Namespace] = accessor;
1909             }
1910         }
1911
1912         static void AddUniqueAccessor(MemberMapping member, INameScope elements, INameScope attributes, bool isSequence) {
1913             if (member.Attribute != null) {
1914                 AddUniqueAccessor(attributes, member.Attribute);
1915             }
1916             else if (!isSequence && member.Elements != null && member.Elements.Length > 0) {
1917                 for (int i = 0; i < member.Elements.Length; i++) {
1918                     AddUniqueAccessor(elements, member.Elements[i]);
1919                 }
1920             }
1921         }
1922
1923         static void CheckForm(XmlSchemaForm form, bool isQualified) {
1924             if (isQualified && form == XmlSchemaForm.Unqualified) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidFormUnqualified));
1925         }
1926
1927         static void CheckNullable(bool isNullable, TypeDesc typeDesc, TypeMapping mapping) {
1928             if (mapping is NullableMapping) return;
1929             if (mapping is SerializableMapping) return;
1930             if (isNullable && !typeDesc.IsNullable) throw new InvalidOperationException(Res.GetString(Res.XmlInvalidIsNullable, typeDesc.FullName));
1931         }
1932
1933         static ElementAccessor CreateElementAccessor(TypeMapping mapping, string ns) {
1934             ElementAccessor element = new ElementAccessor();
1935             bool isAny = mapping.TypeDesc.Kind == TypeKind.Node;
1936             if (!isAny && mapping is SerializableMapping) {
1937                 isAny = ((SerializableMapping)mapping).IsAny;
1938             }
1939             if (isAny) {
1940                 element.Any = true;
1941             }
1942             else {
1943                 element.Name = mapping.DefaultElementName;
1944                 element.Namespace = ns;
1945             }
1946             element.Mapping = mapping;
1947             return element;
1948         }
1949
1950         // will create a shallow type mapping for a top-level type
1951         internal static XmlTypeMapping GetTopLevelMapping(Type type, string defaultNamespace) {
1952             XmlAttributes a = new XmlAttributes(type);
1953             TypeDesc typeDesc = new TypeScope().GetTypeDesc(type);
1954             ElementAccessor element = new ElementAccessor();
1955
1956             if (typeDesc.Kind == TypeKind.Node) {
1957                 element.Any = true;
1958             }
1959             else {
1960                 string ns = a.XmlRoot == null ? defaultNamespace : a.XmlRoot.Namespace;
1961                 string typeName = string.Empty;
1962                 if (a.XmlType != null)
1963                     typeName = a.XmlType.TypeName;
1964                 if (typeName.Length == 0) 
1965                     typeName = type.Name;
1966
1967                 element.Name = XmlConvert.EncodeLocalName(typeName);
1968                 element.Namespace = ns;
1969             }
1970             XmlTypeMapping mapping = new XmlTypeMapping(null, element);
1971             mapping.SetKeyInternal(XmlMapping.GenerateKey(type, a.XmlRoot, defaultNamespace));
1972             return mapping;
1973         }
1974     }
1975     internal class ImportStructWorkItem {
1976         StructModel model;
1977         StructMapping mapping;
1978
1979         internal ImportStructWorkItem(StructModel model, StructMapping mapping) {
1980             this.model = model;
1981             this.mapping = mapping;
1982         }
1983
1984         internal StructModel Model { get { return model; } }
1985         internal StructMapping Mapping { get { return mapping; } }
1986     }
1987
1988     internal class WorkItems {
1989         ArrayList list = new ArrayList();
1990
1991         internal ImportStructWorkItem this[int index] {
1992             get {
1993                 return (ImportStructWorkItem)list[index];
1994             }
1995             set {
1996                 list[index] = value;
1997             }
1998         }
1999
2000         internal int Count {
2001             get {
2002                 return list.Count;
2003             }
2004         }
2005
2006         internal void Add(ImportStructWorkItem item) {
2007             list.Add(item);
2008         }
2009
2010         internal bool Contains(StructMapping mapping) {
2011             return IndexOf(mapping) >= 0;
2012         }
2013
2014         internal int IndexOf(StructMapping mapping) {
2015             for (int i = 0; i < Count; i++) {
2016                 if (this[i].Mapping == mapping)
2017                     return i;
2018             }
2019             return -1;
2020         }
2021
2022         internal void RemoveAt(int index) {
2023             list.RemoveAt(index);
2024         }
2025     }
2026
2027     internal class RecursionLimiter {
2028         int maxDepth;
2029         int depth;
2030         WorkItems deferredWorkItems;
2031
2032         internal RecursionLimiter() {
2033             this.depth = 0;
2034             this.maxDepth = DiagnosticsSwitches.NonRecursiveTypeLoading.Enabled ? 1 : int.MaxValue;
2035         }
2036
2037         internal bool IsExceededLimit { get { return this.depth > this.maxDepth; } }
2038         internal int Depth { get { return this.depth; } set { this.depth = value; } }
2039
2040         internal WorkItems DeferredWorkItems {
2041             get {
2042                 if (deferredWorkItems == null) {
2043                     deferredWorkItems = new WorkItems();
2044                 }
2045                 return deferredWorkItems;
2046             }
2047         }
2048
2049     }
2050
2051
2052
2053 }