Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / Serialization / Mappings.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Mappings.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.Collections;
12     using System.Xml.Schema;
13     using System;
14     using System.Text;
15     using System.ComponentModel;
16     using System.Xml;
17     using System.CodeDom.Compiler;
18
19     // These classes represent a mapping between classes and a particular XML format.
20     // There are two class of mapping information: accessors (such as elements and
21     // attributes), and mappings (which specify the type of an accessor).
22
23     internal abstract class Accessor {
24         string name;
25         object defaultValue = null;
26         string ns;
27         TypeMapping mapping;
28         bool any;
29         string anyNs;
30         bool topLevelInSchema;
31         bool isFixed;
32         bool isOptional;
33         XmlSchemaForm form = XmlSchemaForm.None;
34
35         internal Accessor() { }
36
37         internal TypeMapping Mapping {
38             get { return mapping; }
39             set { mapping = value; }
40         }
41
42         internal object Default {
43             get { return defaultValue; }
44             set { defaultValue = value; }
45         }
46
47         internal bool HasDefault {
48             get { return defaultValue != null && defaultValue != DBNull.Value; }
49         }
50
51         internal virtual string Name {
52             get { return name == null ? string.Empty : name; }
53             set { name = value; }
54         }
55
56         internal bool Any {
57             get { return any; }
58             set { any = value; }
59         }
60
61         internal string AnyNamespaces {
62             get { return anyNs; }
63             set { anyNs = value; }
64         }
65
66         internal string Namespace {
67             get { return ns; }
68             set { ns = value; }
69         }
70
71         internal XmlSchemaForm Form {
72             get { return form; }
73             set { form = value; }
74         }
75
76         internal bool IsFixed {
77             get { return isFixed; }
78             set { isFixed = value; }
79         }
80
81         internal bool IsOptional {
82             get { return isOptional; }
83             set { isOptional = value; }
84         }
85
86         internal bool IsTopLevelInSchema {
87             get { return topLevelInSchema; }
88             set { topLevelInSchema = value; }
89         }
90
91         internal static string EscapeName(string name) {
92             if (name == null || name.Length == 0) return name;
93             return XmlConvert.EncodeLocalName(name);
94         }
95
96         internal static string EscapeQName(string name) {
97             if (name == null || name.Length == 0) return name;
98             int colon = name.LastIndexOf(':');
99             if (colon < 0)
100                 return XmlConvert.EncodeLocalName(name);
101             else {
102                 if (colon == 0 || colon == name.Length - 1)
103                     throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name), "name");
104                 return new XmlQualifiedName(XmlConvert.EncodeLocalName(name.Substring(colon + 1)), XmlConvert.EncodeLocalName(name.Substring(0, colon))).ToString();
105             }
106         }
107
108         internal static string UnescapeName(string name) {
109             return XmlConvert.DecodeName(name);
110         }
111
112         internal string ToString(string defaultNs) {
113             if (Any) {
114                 return (Namespace == null ? "##any" : Namespace) + ":" + Name;
115             }
116             else {
117                 return Namespace == defaultNs ? Name : Namespace + ":" + Name;
118             }
119         }
120     }
121
122     internal class ElementAccessor : Accessor {
123         bool nullable;
124         bool isSoap;
125         bool unbounded = false;
126
127         internal bool IsSoap {
128             get { return isSoap; }
129             set { isSoap = value; }
130         }
131
132         internal bool IsNullable {
133             get { return nullable; }
134             set { nullable = value; }
135         }
136
137         internal bool IsUnbounded {
138             get { return unbounded; }
139             set { unbounded = value; }
140         }
141
142         internal ElementAccessor Clone() {
143             ElementAccessor newAccessor = new ElementAccessor();
144             newAccessor.nullable = this.nullable;
145             newAccessor.IsTopLevelInSchema = this.IsTopLevelInSchema;
146             newAccessor.Form = this.Form;
147             newAccessor.isSoap = this.isSoap;
148             newAccessor.Name = this.Name;
149             newAccessor.Default = this.Default;
150             newAccessor.Namespace = this.Namespace;
151             newAccessor.Mapping = this.Mapping;
152             newAccessor.Any = this.Any;
153
154             return newAccessor;
155         }
156     }
157
158     internal class ChoiceIdentifierAccessor : Accessor {
159         string memberName;
160         string[] memberIds;
161         MemberInfo memberInfo;
162
163         internal string MemberName {
164             get { return memberName; }
165             set { memberName = value; }
166         }
167
168         internal string[] MemberIds {
169             get { return memberIds; }
170             set { memberIds = value; }
171         }
172
173         internal MemberInfo MemberInfo {
174             get { return memberInfo; }
175             set { memberInfo = value; }
176         }
177     }
178
179     internal class TextAccessor : Accessor {
180     }
181
182     internal class XmlnsAccessor : Accessor {
183     }
184
185     internal class AttributeAccessor : Accessor {
186         bool isSpecial;
187         bool isList;
188
189         internal bool IsSpecialXmlNamespace {
190             get { return isSpecial; }
191         }
192
193         internal bool IsList {
194             get { return isList; }
195             set { isList = value; }
196         }
197
198         internal void CheckSpecial() {
199             int colon = Name.LastIndexOf(':');
200
201             if (colon >= 0) {
202                 if (!Name.StartsWith("xml:", StringComparison.Ordinal)) {
203                     throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidNameChars, Name));
204                 }
205                 Name = Name.Substring("xml:".Length);
206                 Namespace = XmlReservedNs.NsXml;
207                 isSpecial = true;
208             }
209             else {
210                 if (Namespace == XmlReservedNs.NsXml) {
211                     isSpecial = true;
212                 }
213                 else {
214                     isSpecial = false;
215                 }
216             }
217             if (isSpecial) {
218                 Form = XmlSchemaForm.Qualified;
219             }
220         }
221     }
222
223     internal abstract class Mapping {
224         bool isSoap;
225
226         internal Mapping() { }
227
228         protected Mapping(Mapping mapping)
229         {
230             this.isSoap = mapping.isSoap;
231         }
232
233         internal bool IsSoap {
234             get { return isSoap; }
235             set { isSoap = value; }
236         }
237     }
238
239     internal abstract class TypeMapping : Mapping {
240         TypeDesc typeDesc;
241         string typeNs;
242         string typeName;
243         bool referencedByElement;
244         bool referencedByTopLevelElement;
245         bool includeInSchema = true;
246         bool reference = false;
247
248         internal bool ReferencedByTopLevelElement {
249             get { return referencedByTopLevelElement; }
250             set { referencedByTopLevelElement = value; }
251         }
252
253         internal bool ReferencedByElement {
254             get { return referencedByElement || referencedByTopLevelElement; }
255             set { referencedByElement = value; }
256         }
257         internal string Namespace {
258             get { return typeNs; }
259             set { typeNs = value; }
260         }
261
262         internal string TypeName {
263             get { return typeName; }
264             set { typeName = value; }
265         }
266
267         internal TypeDesc TypeDesc {
268             get { return typeDesc; }
269             set { typeDesc = value; }
270         }
271
272         internal bool IncludeInSchema {
273             get { return includeInSchema; }
274             set { includeInSchema = value; }
275         }
276
277         internal virtual bool IsList {
278             get { return false; }
279             set { }
280         }
281
282         internal bool IsReference {
283             get { return reference; }
284             set { reference = value; }
285         }
286
287         internal bool IsAnonymousType {
288             get { return typeName == null || typeName.Length == 0; }
289         }
290
291         internal virtual string DefaultElementName {
292             get { return IsAnonymousType ? XmlConvert.EncodeLocalName(typeDesc.Name) : typeName; }
293         }
294     }
295
296     internal class PrimitiveMapping : TypeMapping {
297         bool isList;
298
299         internal override bool IsList {
300             get { return isList; }
301             set { isList = value; }
302         }
303     }
304
305     internal class NullableMapping : TypeMapping {
306         TypeMapping baseMapping;
307
308         internal TypeMapping BaseMapping {
309             get { return baseMapping; }
310             set { baseMapping = value; }
311         }
312
313         internal override string DefaultElementName {
314             get { return BaseMapping.DefaultElementName; }
315         }
316     }
317
318     internal class ArrayMapping : TypeMapping {
319         ElementAccessor[] elements;
320         ElementAccessor[] sortedElements;
321         ArrayMapping next;
322         StructMapping topLevelMapping;
323
324         internal ElementAccessor[] Elements {
325             get { return elements; }
326             set { elements = value; sortedElements = null; }
327         }
328
329         internal ElementAccessor[] ElementsSortedByDerivation {
330             get {
331                 if (sortedElements != null)
332                     return sortedElements;
333                 if (elements == null)
334                     return null;
335                 sortedElements = new ElementAccessor[elements.Length];
336                 Array.Copy(elements, 0, sortedElements, 0, elements.Length);
337                 AccessorMapping.SortMostToLeastDerived(sortedElements);
338                 return sortedElements;
339             }
340         }
341
342
343         internal ArrayMapping Next {
344             get { return next; }
345             set { next = value; }
346         }
347
348         internal StructMapping TopLevelMapping {
349             get { return topLevelMapping; }
350             set { topLevelMapping = value; }
351         }
352     }
353
354     internal class EnumMapping : PrimitiveMapping {
355         ConstantMapping[] constants;
356         bool isFlags;
357
358         internal bool IsFlags {
359             get { return isFlags; }
360             set { isFlags = value; }
361         }
362
363         internal ConstantMapping[] Constants {
364             get { return constants; }
365             set { constants = value; }
366         }
367     }
368
369     internal class ConstantMapping : Mapping {
370         string xmlName;
371         string name;
372         long value;
373
374         internal string XmlName {
375             get { return xmlName == null ? string.Empty : xmlName; }
376             set { xmlName = value; }
377         }
378
379         internal string Name {
380             get { return name == null ? string.Empty : name; }
381             set { this.name = value; }
382         }
383
384         internal long Value {
385             get { return value; }
386             set { this.value = value; }
387         }
388     }
389
390     internal class StructMapping : TypeMapping, INameScope {
391         MemberMapping[] members;
392         StructMapping baseMapping;
393         StructMapping derivedMappings;
394         StructMapping nextDerivedMapping;
395         MemberMapping xmlnsMember = null;
396         bool hasSimpleContent;
397         bool openModel;
398         bool isSequence;
399         NameTable elements;
400         NameTable attributes;
401         CodeIdentifiers scope;
402
403         internal StructMapping BaseMapping {
404             get { return baseMapping; }
405             set {
406                 baseMapping = value;
407                 if (!IsAnonymousType && baseMapping != null) {
408                     nextDerivedMapping = baseMapping.derivedMappings;
409                     baseMapping.derivedMappings = this;
410                 }
411                 if (value.isSequence && !isSequence) {
412                     isSequence = true;
413                     if (baseMapping.IsSequence) {
414                         for (StructMapping derived = derivedMappings; derived != null; derived = derived.NextDerivedMapping) {
415                             derived.SetSequence();
416                         }
417                     }
418                 }
419             }
420         }
421
422         internal StructMapping DerivedMappings {
423             get { return derivedMappings; }
424         }
425
426         internal bool IsFullyInitialized {
427             get { return baseMapping != null && Members != null; }
428         }
429
430         internal NameTable LocalElements {
431             get {
432                 if (elements == null)
433                     elements = new NameTable();
434                 return elements;
435             }
436         }
437         internal NameTable LocalAttributes {
438             get {
439                 if (attributes == null)
440                     attributes = new NameTable();
441                 return attributes;
442             }
443         }
444         object INameScope.this[string name, string ns] {
445             get {
446                 object named = LocalElements[name, ns];
447                 if (named != null)
448                     return named;
449                 if (baseMapping != null)
450                     return ((INameScope)baseMapping)[name, ns];
451                 return null;
452             }
453             set {
454                 LocalElements[name, ns] = value;
455             }
456         }
457         internal StructMapping NextDerivedMapping {
458             get { return nextDerivedMapping; }
459         }
460
461         internal bool HasSimpleContent {
462             get { return hasSimpleContent; }
463         }
464
465         internal bool HasXmlnsMember {
466             get {
467                 StructMapping mapping = this;
468                 while (mapping != null) {
469                     if (mapping.XmlnsMember != null)
470                         return true;
471                     mapping = mapping.BaseMapping;
472                 }
473                 return false;
474             }
475         }
476
477         internal MemberMapping[] Members {
478             get { return members; }
479             set { members = value; }
480         }
481
482         internal MemberMapping XmlnsMember {
483             get { return xmlnsMember; }
484             set { xmlnsMember = value; }
485         }
486
487         internal bool IsOpenModel {
488             get { return openModel; }
489             set { openModel = value; }
490         }
491
492         internal CodeIdentifiers Scope {
493             get {
494                 if (scope == null)
495                     scope = new CodeIdentifiers();
496                 return scope;
497             }
498             set { scope = value; }
499         }
500
501         internal MemberMapping FindDeclaringMapping(MemberMapping member, out StructMapping declaringMapping, string parent) {
502             declaringMapping = null;
503             if (BaseMapping != null) {
504                 MemberMapping baseMember = BaseMapping.FindDeclaringMapping(member, out declaringMapping, parent);
505                 if (baseMember != null) return baseMember;
506             }
507             if (members == null) return null;
508
509             for (int i = 0; i < members.Length; i++) {
510                 if (members[i].Name == member.Name) {
511                     if (members[i].TypeDesc != member.TypeDesc)
512                         throw new InvalidOperationException(Res.GetString(Res.XmlHiddenMember, parent, member.Name, member.TypeDesc.FullName, this.TypeName, members[i].Name, members[i].TypeDesc.FullName));
513                     else if (!members[i].Match(member)) {
514                         throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXmlOverride, parent, member.Name, this.TypeName, members[i].Name));
515                     }
516                     declaringMapping = this;
517                     return members[i];
518                 }
519             }
520             return null;
521         }
522         internal bool Declares(MemberMapping member, string parent) {
523             StructMapping m;
524             return (FindDeclaringMapping(member, out m, parent) != null);
525         }
526
527         internal void SetContentModel(TextAccessor text, bool hasElements) {
528             if (BaseMapping == null || BaseMapping.TypeDesc.IsRoot) {
529                 hasSimpleContent = !hasElements && text != null && !text.Mapping.IsList;
530             }
531             else if (BaseMapping.HasSimpleContent) {
532                 if (text != null || hasElements) {
533                     // we can only extent a simleContent type with attributes
534                     throw new InvalidOperationException(Res.GetString(Res.XmlIllegalSimpleContentExtension, TypeDesc.FullName, BaseMapping.TypeDesc.FullName));
535                 }
536                 else {
537                     hasSimpleContent = true;
538                 }
539             }
540             else {
541                 hasSimpleContent = false;
542             }
543             if (!hasSimpleContent && text != null && !text.Mapping.TypeDesc.CanBeTextValue) {
544                 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalTypedTextAttribute, TypeDesc.FullName, text.Name, text.Mapping.TypeDesc.FullName));
545             }
546         }
547
548         internal bool HasElements {
549             get { return elements != null && elements.Values.Count > 0; }
550         }
551
552         internal bool HasExplicitSequence() {
553             if (members != null) {
554                 for (int i = 0; i < members.Length; i++) {
555                     if (members[i].IsParticle && members[i].IsSequence) {
556                         return true;
557                     }
558                 }
559             }
560             return (baseMapping != null && baseMapping.HasExplicitSequence());
561         }
562
563         internal void SetSequence() {
564             if (TypeDesc.IsRoot)
565                 return;
566
567             StructMapping start = this;
568
569             // find first mapping that does not have the sequence set
570             while (!start.BaseMapping.IsSequence && start.BaseMapping != null && !start.BaseMapping.TypeDesc.IsRoot)
571                 start = start.BaseMapping;
572
573             start.IsSequence = true;
574             for (StructMapping derived = start.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
575                 derived.SetSequence();
576             }
577         }
578
579         internal bool IsSequence {
580             get { return isSequence && !TypeDesc.IsRoot; }
581             set { isSequence = value; }
582         }
583     }
584
585     internal abstract class AccessorMapping : Mapping {
586         TypeDesc typeDesc;
587         AttributeAccessor attribute;
588         ElementAccessor[] elements;
589         ElementAccessor[] sortedElements;
590         TextAccessor text;
591         ChoiceIdentifierAccessor choiceIdentifier;
592         XmlnsAccessor xmlns;
593         bool ignore;
594         
595         internal AccessorMapping()
596         { }
597
598         protected AccessorMapping(AccessorMapping mapping)
599             : base(mapping)
600         {
601             this.typeDesc = mapping.typeDesc;
602             this.attribute = mapping.attribute;
603             this.elements = mapping.elements;
604             this.sortedElements = mapping.sortedElements;
605             this.text = mapping.text;
606             this.choiceIdentifier = mapping.choiceIdentifier;
607             this.xmlns = mapping.xmlns;
608             this.ignore = mapping.ignore;
609         }
610
611         internal bool IsAttribute {
612             get { return attribute != null; }
613         }
614
615         internal bool IsText {
616             get { return text != null && (elements == null || elements.Length == 0); }
617         }
618
619         internal bool IsParticle {
620             get { return (elements != null && elements.Length > 0); }
621         }
622
623         internal TypeDesc TypeDesc {
624             get { return typeDesc; }
625             set { typeDesc = value; }
626         }
627
628         internal AttributeAccessor Attribute {
629             get { return attribute; }
630             set { attribute = value; }
631         }
632
633         internal ElementAccessor[] Elements {
634             get { return elements; }
635             set { elements = value; sortedElements = null; }
636         }
637
638         internal static void SortMostToLeastDerived(ElementAccessor[] elements) {
639             Array.Sort(elements, new AccessorComparer());
640         }
641
642         internal class AccessorComparer : IComparer {
643             public int Compare(object o1, object o2) {
644                 if (o1 == o2)
645                     return 0;
646                 Accessor a1 = (Accessor)o1;
647                 Accessor a2 = (Accessor)o2;
648                 int w1 = a1.Mapping.TypeDesc.Weight;
649                 int w2 = a2.Mapping.TypeDesc.Weight;
650                 if (w1 == w2)
651                     return 0;
652                 if (w1 < w2)
653                     return 1;
654                 return -1;
655             }
656         }
657
658         internal ElementAccessor[] ElementsSortedByDerivation {
659             get {
660                 if (sortedElements != null)
661                     return sortedElements;
662                 if (elements == null)
663                     return null;
664                 sortedElements = new ElementAccessor[elements.Length];
665                 Array.Copy(elements, 0, sortedElements, 0, elements.Length);
666                 SortMostToLeastDerived(sortedElements);
667                 return sortedElements;
668             }
669         }
670
671         internal TextAccessor Text {
672             get { return text; }
673             set { text = value; }
674         }
675
676         internal ChoiceIdentifierAccessor ChoiceIdentifier {
677             get { return choiceIdentifier; }
678             set { choiceIdentifier = value; }
679         }
680
681         internal XmlnsAccessor Xmlns {
682             get { return xmlns; }
683             set { xmlns = value; }
684         }
685
686         internal bool Ignore {
687             get { return ignore; }
688             set { ignore = value; }
689         }
690
691         internal Accessor Accessor {
692             get {
693                 if (xmlns != null) return xmlns;
694                 if (attribute != null) return attribute;
695                 if (elements != null && elements.Length > 0) return elements[0];
696                 return text;
697             }
698         }
699
700         static bool IsNeedNullableMember(ElementAccessor element) {
701             if (element.Mapping is ArrayMapping) {
702                 ArrayMapping arrayMapping = (ArrayMapping)element.Mapping;
703                 if (arrayMapping.Elements != null && arrayMapping.Elements.Length == 1) {
704                     return IsNeedNullableMember(arrayMapping.Elements[0]);
705                 }
706                 return false;
707             }
708             else {
709                 return element.IsNullable && element.Mapping.TypeDesc.IsValueType;
710             }
711         }
712
713         internal bool IsNeedNullable {
714             get {
715                 if (xmlns != null) return false;
716                 if (attribute != null) return false;
717                 if (elements != null && elements.Length == 1) {
718                     return IsNeedNullableMember(elements[0]);
719                 }
720                 return false;
721             }
722         }
723
724         internal static bool ElementsMatch(ElementAccessor[] a, ElementAccessor[] b) {
725             if (a == null) {
726                 if (b == null)
727                     return true;
728                 return false;
729             }
730             if (b == null)
731                 return false;
732             if (a.Length != b.Length)
733                 return false;
734             for (int i = 0; i < a.Length; i++) {
735                 if (a[i].Name != b[i].Name || a[i].Namespace != b[i].Namespace || a[i].Form != b[i].Form || a[i].IsNullable != b[i].IsNullable)
736                     return false;
737             }
738             return true;
739         }
740
741         internal bool Match(AccessorMapping mapping) {
742             if (Elements != null && Elements.Length > 0) {
743                 if (!ElementsMatch(Elements, mapping.Elements)) {
744                     return false;
745                 }
746                 if (Text == null) {
747                     return (mapping.Text == null);
748                 }
749             }
750             if (Attribute != null) {
751                 if (mapping.Attribute == null)
752                     return false;
753                 return (Attribute.Name == mapping.Attribute.Name && Attribute.Namespace == mapping.Attribute.Namespace && Attribute.Form == mapping.Attribute.Form);
754             }
755             if (Text != null) {
756                 return (mapping.Text != null);
757             }
758             return (mapping.Accessor == null);
759         }
760     }
761
762     internal class MemberMappingComparer : IComparer {
763         public int Compare(object o1, object o2) {
764             MemberMapping m1 = (MemberMapping)o1;
765             MemberMapping m2 = (MemberMapping)o2;
766
767             bool m1Text = m1.IsText;
768             if (m1Text) {
769                 if (m2.IsText)
770                     return 0;
771                 return 1;
772             }
773             else if (m2.IsText)
774                 return -1;
775
776             if (m1.SequenceId < 0 && m2.SequenceId < 0)
777                 return 0;
778             if (m1.SequenceId < 0)
779                 return 1;
780             if (m2.SequenceId < 0)
781                 return -1;
782             if (m1.SequenceId < m2.SequenceId)
783                 return -1;
784             if (m1.SequenceId > m2.SequenceId)
785                 return 1;
786             return 0;
787         }
788     }
789
790     internal class MemberMapping : AccessorMapping {
791         string name;
792         bool checkShouldPersist;
793         SpecifiedAccessor checkSpecified;
794         bool isReturnValue;
795         bool readOnly = false;
796         int sequenceId = -1;
797         MemberInfo memberInfo;
798         MemberInfo checkSpecifiedMemberInfo;
799         MethodInfo checkShouldPersistMethodInfo;
800
801         internal MemberMapping() { }
802         
803         MemberMapping(MemberMapping mapping)
804             : base(mapping)
805         {
806             this.name = mapping.name;
807             this.checkShouldPersist = mapping.checkShouldPersist;
808             this.checkSpecified = mapping.checkSpecified;
809             this.isReturnValue = mapping.isReturnValue;
810             this.readOnly = mapping.readOnly;
811             this.sequenceId = mapping.sequenceId;
812             this.memberInfo = mapping.memberInfo;
813             this.checkSpecifiedMemberInfo = mapping.checkSpecifiedMemberInfo;
814             this.checkShouldPersistMethodInfo = mapping.checkShouldPersistMethodInfo;
815         }
816
817         internal bool CheckShouldPersist {
818             get { return checkShouldPersist; }
819             set { checkShouldPersist = value; }
820         }
821
822         internal SpecifiedAccessor CheckSpecified {
823             get { return checkSpecified; }
824             set { checkSpecified = value; }
825         }
826
827         internal string Name {
828             get { return name == null ? string.Empty : name; }
829             set { name = value; }
830         }
831
832         internal MemberInfo MemberInfo {
833             get { return memberInfo; }
834             set { memberInfo = value; }
835         }
836
837         internal MemberInfo CheckSpecifiedMemberInfo {
838             get { return checkSpecifiedMemberInfo; }
839             set { checkSpecifiedMemberInfo = value; }
840         }
841
842         internal MethodInfo CheckShouldPersistMethodInfo {
843             get { return checkShouldPersistMethodInfo; }
844             set { checkShouldPersistMethodInfo = value; }
845         }
846
847         internal bool IsReturnValue {
848             get { return isReturnValue; }
849             set { isReturnValue = value; }
850         }
851
852         internal bool ReadOnly {
853             get { return readOnly; }
854             set { readOnly = value; }
855         }
856
857         internal bool IsSequence {
858             get { return sequenceId >= 0; }
859         }
860
861         internal int SequenceId {
862             get { return sequenceId; }
863             set { sequenceId = value; }
864         }
865
866         string GetNullableType(TypeDesc td) {
867             // SOAP encoded arrays not mapped to Nullable<T> since they always derive from soapenc:Array
868             if (td.IsMappedType || (!td.IsValueType && (Elements[0].IsSoap || td.ArrayElementTypeDesc == null)))
869                 return td.FullName;
870             if (td.ArrayElementTypeDesc != null) {
871                 return GetNullableType(td.ArrayElementTypeDesc) + "[]";
872             }
873             return "System.Nullable`1[" + td.FullName + "]";
874         }
875
876         internal MemberMapping Clone()
877         {
878             return new MemberMapping(this);
879         }
880
881         internal string GetTypeName(CodeDomProvider codeProvider) {
882             if (IsNeedNullable && codeProvider.Supports(GeneratorSupport.GenericTypeReference)) {
883                 return GetNullableType(TypeDesc);
884             }
885             return TypeDesc.FullName;
886         }
887     }
888
889     internal class MembersMapping : TypeMapping {
890         MemberMapping[] members;
891         bool hasWrapperElement = true;
892         bool validateRpcWrapperElement;
893         bool writeAccessors = true;
894         MemberMapping xmlnsMember = null;
895
896         internal MemberMapping[] Members {
897             get { return members; }
898             set { members = value; }
899         }
900
901         internal MemberMapping XmlnsMember {
902             get { return xmlnsMember; }
903             set { xmlnsMember = value; }
904         }
905
906         internal bool HasWrapperElement {
907             get { return hasWrapperElement; }
908             set { hasWrapperElement = value; }
909         }
910
911         internal bool ValidateRpcWrapperElement {
912             get { return validateRpcWrapperElement; }
913             set { validateRpcWrapperElement = value; }
914         }
915
916         internal bool WriteAccessors {
917             get { return writeAccessors; }
918             set { writeAccessors = value; }
919         }
920     }
921
922     internal class SpecialMapping : TypeMapping {
923         bool namedAny;
924
925         internal bool NamedAny {
926             get { return namedAny; }
927             set { namedAny = value; }
928         }
929     }
930
931     internal class SerializableMapping : SpecialMapping {
932         XmlSchema schema;
933         Type type;
934         bool needSchema = true;
935
936         // new implementation of the IXmlSerializable
937         MethodInfo getSchemaMethod;
938         XmlQualifiedName xsiType;
939         XmlSchemaType xsdType;
940         XmlSchemaSet schemas;
941         bool any;
942         string namespaces;
943
944         SerializableMapping baseMapping;
945         SerializableMapping derivedMappings;
946         SerializableMapping nextDerivedMapping;
947         SerializableMapping next; // all mappings with the same qname
948
949         internal SerializableMapping() { }
950         internal SerializableMapping(MethodInfo getSchemaMethod, bool any, string ns) {
951             this.getSchemaMethod = getSchemaMethod;
952             this.any = any;
953             this.Namespace = ns;
954             needSchema = getSchemaMethod != null;
955         }
956
957         internal SerializableMapping(XmlQualifiedName xsiType, XmlSchemaSet schemas) {
958             this.xsiType = xsiType;
959             this.schemas = schemas;
960             this.TypeName = xsiType.Name;
961             this.Namespace = xsiType.Namespace;
962             needSchema = false;
963         }
964
965         internal void SetBaseMapping(SerializableMapping mapping) {
966             baseMapping = mapping;
967             if (baseMapping != null) {
968                 nextDerivedMapping = baseMapping.derivedMappings;
969                 baseMapping.derivedMappings = this;
970                 if (this == nextDerivedMapping) {
971                     throw new InvalidOperationException(Res.GetString(Res.XmlCircularDerivation, TypeDesc.FullName));
972                 }
973             }
974         }
975
976         internal bool IsAny {
977             get {
978                 if (any)
979                     return true;
980                 if (getSchemaMethod == null)
981                     return false;
982                 if (needSchema && typeof(XmlSchemaType).IsAssignableFrom(getSchemaMethod.ReturnType))
983                     return false;
984                 RetrieveSerializableSchema();
985                 return any;
986             }
987         }
988
989         internal string NamespaceList {
990             get {
991                 RetrieveSerializableSchema();
992                 if (namespaces == null) {
993                     if (schemas != null) {
994                         StringBuilder anyNamespaces = new StringBuilder();
995                         foreach (XmlSchema s in schemas.Schemas()) {
996                             if (s.TargetNamespace != null && s.TargetNamespace.Length > 0) {
997                                 if (anyNamespaces.Length > 0)
998                                     anyNamespaces.Append(" ");
999                                 anyNamespaces.Append(s.TargetNamespace);
1000                             }
1001                         }
1002                         namespaces = anyNamespaces.ToString();
1003                     }
1004                     else {
1005                         namespaces = string.Empty;
1006                     }
1007                 }
1008                 return namespaces;
1009             }
1010         }
1011
1012         internal SerializableMapping DerivedMappings {
1013             get {
1014                 return derivedMappings;
1015             }
1016         }
1017
1018         internal SerializableMapping NextDerivedMapping {
1019             get {
1020                 return nextDerivedMapping;
1021             }
1022         }
1023
1024         internal SerializableMapping Next {
1025             get { return next; }
1026             set { next = value; }
1027         }
1028
1029         internal Type Type {
1030             get { return type; }
1031             set { type = value; }
1032         }
1033
1034         internal XmlSchemaSet Schemas {
1035             get {
1036                 RetrieveSerializableSchema();
1037                 return schemas;
1038             }
1039         }
1040
1041         internal XmlSchema Schema {
1042             get {
1043                 RetrieveSerializableSchema();
1044                 return schema;
1045             }
1046         }
1047
1048         internal XmlQualifiedName XsiType {
1049             get {
1050                 if (!needSchema)
1051                     return xsiType;
1052                 if (getSchemaMethod == null)
1053                     return null;
1054                 if (typeof(XmlSchemaType).IsAssignableFrom(getSchemaMethod.ReturnType))
1055                     return null;
1056                 RetrieveSerializableSchema();
1057                 return xsiType;
1058             }
1059         }
1060
1061         internal XmlSchemaType XsdType {
1062             get {
1063                 RetrieveSerializableSchema();
1064                 return xsdType;
1065             }
1066         }
1067
1068         internal static void ValidationCallbackWithErrorCode(object sender, ValidationEventArgs args) {
1069             // 
1070             if (args.Severity == XmlSeverityType.Error)
1071                 throw new InvalidOperationException(Res.GetString(Res.XmlSerializableSchemaError, typeof(IXmlSerializable).Name, args.Message));
1072         }
1073
1074         internal void CheckDuplicateElement(XmlSchemaElement element, string elementNs) {
1075             if (element == null)
1076                 return;
1077
1078             // only check duplicate definitions for top-level element
1079             if (element.Parent == null || !(element.Parent is XmlSchema))
1080                 return;
1081
1082             XmlSchemaObjectTable elements = null;
1083             if (Schema != null && Schema.TargetNamespace == elementNs) {
1084                 XmlSchemas.Preprocess(Schema);
1085                 elements = Schema.Elements;
1086             }
1087             else if (Schemas != null) {
1088                 elements = Schemas.GlobalElements;
1089             }
1090             else {
1091                 return;
1092             }
1093             foreach (XmlSchemaElement e in elements.Values) {
1094                 if (e.Name == element.Name && e.QualifiedName.Namespace == elementNs) {
1095                     if (Match(e, element))
1096                         return;
1097                     // XmlSerializableRootDupName=Cannot reconcile schema for '{0}'. Please use [XmlRoot] attribute to change name or namepace of the top-level element to avoid duplicate element declarations: element name='{1} namespace='{2}'.
1098                     throw new InvalidOperationException(Res.GetString(Res.XmlSerializableRootDupName, getSchemaMethod.DeclaringType.FullName, e.Name, elementNs));
1099                 }
1100             }
1101         }
1102
1103         bool Match(XmlSchemaElement e1, XmlSchemaElement e2) {
1104             if (e1.IsNillable != e2.IsNillable)
1105                 return false;
1106             if (e1.RefName != e2.RefName)
1107                 return false;
1108             if (e1.SchemaType != e2.SchemaType)
1109                 return false;
1110             if (e1.SchemaTypeName != e2.SchemaTypeName)
1111                 return false;
1112             if (e1.MinOccurs != e2.MinOccurs)
1113                 return false;
1114             if (e1.MaxOccurs != e2.MaxOccurs)
1115                 return false;
1116             if (e1.IsAbstract != e2.IsAbstract)
1117                 return false;
1118             if (e1.DefaultValue != e2.DefaultValue)
1119                 return false;
1120             if (e1.SubstitutionGroup != e2.SubstitutionGroup)
1121                 return false;
1122             return true;
1123         }
1124
1125         void RetrieveSerializableSchema() {
1126             if (needSchema) {
1127                 needSchema = false;
1128                 if (getSchemaMethod != null) {
1129                     // get the type info
1130                     if (schemas == null)
1131                         schemas = new XmlSchemaSet();
1132                     object typeInfo = getSchemaMethod.Invoke(null, new object[] { schemas });
1133                     xsiType = XmlQualifiedName.Empty;
1134
1135                     if (typeInfo != null) {
1136                         if (typeof(XmlSchemaType).IsAssignableFrom(getSchemaMethod.ReturnType)) {
1137                             xsdType = (XmlSchemaType)typeInfo;
1138                             // check if type is named
1139                             xsiType = xsdType.QualifiedName;
1140                         }
1141                         else if (typeof(XmlQualifiedName).IsAssignableFrom(getSchemaMethod.ReturnType)) {
1142                             xsiType = (XmlQualifiedName)typeInfo;
1143                             if (xsiType.IsEmpty) {
1144                                 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaEmptyTypeName, type.FullName, getSchemaMethod.Name));
1145                             }
1146                         }
1147                         else {
1148                             throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaMethodReturnType, type.Name, getSchemaMethod.Name, typeof(XmlSchemaProviderAttribute).Name, typeof(XmlQualifiedName).FullName));
1149                         }
1150                     }
1151                     else {
1152                         any = true;
1153                     }
1154
1155                     // make sure that user-specified schemas are valid
1156                     schemas.ValidationEventHandler += new ValidationEventHandler(ValidationCallbackWithErrorCode);
1157                     schemas.Compile();
1158                     // at this point we verified that the information returned by the IXmlSerializable is valid
1159                     // Now check to see if the type was referenced before:
1160                     // 
1161                     if (!xsiType.IsEmpty) {
1162                         // try to find the type in the schemas collection
1163                         if (xsiType.Namespace != XmlSchema.Namespace) {
1164                             ArrayList srcSchemas = (ArrayList)schemas.Schemas(xsiType.Namespace);
1165
1166                             if (srcSchemas.Count == 0) {
1167                                 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, xsiType.Namespace));
1168                             }
1169                             if (srcSchemas.Count > 1) {
1170                                 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaInclude, xsiType.Namespace, getSchemaMethod.DeclaringType.FullName, getSchemaMethod.Name));
1171                             }
1172                             XmlSchema s = (XmlSchema)srcSchemas[0];
1173                             if (s == null) {
1174                                 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, xsiType.Namespace));
1175                             }
1176                             xsdType = (XmlSchemaType)s.SchemaTypes[xsiType];
1177                             if (xsdType == null) {
1178                                 throw new InvalidOperationException(Res.GetString(Res.XmlGetSchemaTypeMissing, getSchemaMethod.DeclaringType.FullName, getSchemaMethod.Name, xsiType.Name, xsiType.Namespace));
1179                             }
1180                             xsdType = xsdType.Redefined != null ? xsdType.Redefined : xsdType;
1181                         }
1182                     }
1183                 }
1184                 else {
1185                     IXmlSerializable serializable = (IXmlSerializable)Activator.CreateInstance(type);
1186                     schema = serializable.GetSchema();
1187
1188                     if (schema != null) {
1189                         if (schema.Id == null || schema.Id.Length == 0) throw new InvalidOperationException(Res.GetString(Res.XmlSerializableNameMissing1, type.FullName));
1190                     }
1191                 }
1192             }
1193         }
1194     }
1195 }
1196