[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Runtime / Serialization / DataContract.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.Runtime.Serialization
5 {
6     using System;
7     using System.CodeDom;
8     using System.Collections;
9     using System.Collections.Generic;
10     using System.Diagnostics.CodeAnalysis;
11     using System.Globalization;
12     using System.Reflection;
13     using System.Runtime.CompilerServices;
14 #if !NO_CONFIGURATION
15     using System.Runtime.Serialization.Configuration;
16 #endif
17     using System.Runtime.Serialization.Diagnostics.Application;
18     using System.Security;
19     using System.Text;
20     using System.Xml;
21     using System.Xml.Schema;
22     using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
23     using System.Text.RegularExpressions;
24
25 #if USE_REFEMIT
26     public abstract class DataContract
27 #else
28     internal abstract class DataContract
29 #endif
30     {
31         [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the type name. Statically cached and used from IL generated code.")]
32         [SecurityCritical]
33         XmlDictionaryString name;
34
35         [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the type name. Statically cached and used from IL generated code.")]
36         [SecurityCritical]
37         XmlDictionaryString ns;
38
39         [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization."
40             + " Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
41         [SecurityCritical]
42         DataContractCriticalHelper helper;
43
44         [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
45             Safe = "Doesn't leak anything.")]
46         [SecuritySafeCritical]
47         protected DataContract(DataContractCriticalHelper helper)
48         {
49             this.helper = helper;
50             this.name = helper.Name;
51             this.ns = helper.Namespace;
52         }
53
54         internal static DataContract GetDataContract(Type type)
55         {
56             return GetDataContract(type.TypeHandle, type, SerializationMode.SharedContract);
57         }
58
59         internal static DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
60         {
61             int id = GetId(typeHandle);
62             return GetDataContract(id, typeHandle, mode);
63         }
64
65         internal static DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle, SerializationMode mode)
66         {
67             DataContract dataContract = GetDataContractSkipValidation(id, typeHandle, null);
68             dataContract = dataContract.GetValidContract(mode);
69
70             return dataContract;
71         }
72
73         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up DataContract .",
74             Safe = "Read only access.")]
75         [SecuritySafeCritical]
76         internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type)
77         {
78             return DataContractCriticalHelper.GetDataContractSkipValidation(id, typeHandle, type);
79         }
80
81         internal static DataContract GetGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
82         {
83             DataContract dataContract = GetGetOnlyCollectionDataContractSkipValidation(id, typeHandle, type);
84             dataContract = dataContract.GetValidContract(mode);
85             if (dataContract is ClassDataContract)
86             {
87                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.ClassDataContractReturnedForGetOnlyCollection, DataContract.GetClrTypeFullName(dataContract.UnderlyingType))));
88             }
89             return dataContract;
90         }
91
92         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up DataContract .",
93             Safe = "Read only access.")]
94         [SecuritySafeCritical]
95         internal static DataContract GetGetOnlyCollectionDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type)
96         {
97             return DataContractCriticalHelper.GetGetOnlyCollectionDataContractSkipValidation(id, typeHandle, type);
98         }
99
100         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up DataContract .",
101             Safe = "Read only access; doesn't modify any static information.")]
102         [SecuritySafeCritical]
103         internal static DataContract GetDataContractForInitialization(int id)
104         {
105             return DataContractCriticalHelper.GetDataContractForInitialization(id);
106         }
107
108         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up id for DataContract .",
109             Safe = "Read only access; doesn't modify any static information.")]
110         [SecuritySafeCritical]
111         internal static int GetIdForInitialization(ClassDataContract classContract)
112         {
113             return DataContractCriticalHelper.GetIdForInitialization(classContract);
114         }
115
116         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up id assigned to a particular type.",
117             Safe = "Read only access.")]
118         [SecuritySafeCritical]
119         internal static int GetId(RuntimeTypeHandle typeHandle)
120         {
121             return DataContractCriticalHelper.GetId(typeHandle);
122         }
123
124         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up DataContract.",
125             Safe = "Read only access.")]
126         [SecuritySafeCritical]
127         public static DataContract GetBuiltInDataContract(Type type)
128         {
129             return DataContractCriticalHelper.GetBuiltInDataContract(type);
130         }
131
132         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up DataContract.",
133             Safe = "Read only access.")]
134         [SecuritySafeCritical]
135         public static DataContract GetBuiltInDataContract(string name, string ns)
136         {
137             return DataContractCriticalHelper.GetBuiltInDataContract(name, ns);
138         }
139
140         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up DataContract.",
141             Safe = "Read only access.")]
142         [SecuritySafeCritical]
143         public static DataContract GetBuiltInDataContract(string typeName)
144         {
145             return DataContractCriticalHelper.GetBuiltInDataContract(typeName);
146         }
147
148         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up string reference to use for a namespace string.",
149             Safe = "Read only access.")]
150         [SecuritySafeCritical]
151         internal static string GetNamespace(string key)
152         {
153             return DataContractCriticalHelper.GetNamespace(key);
154         }
155
156         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to look up XmlDictionaryString for a string.",
157             Safe = "Read only access.")]
158         [SecuritySafeCritical]
159         internal static XmlDictionaryString GetClrTypeString(string key)
160         {
161             return DataContractCriticalHelper.GetClrTypeString(key);
162         }
163
164         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical static cache to remove invalid DataContract if it has been added to cache.",
165             Safe = "Doesn't leak any information.")]
166         [SecuritySafeCritical]
167         internal static void ThrowInvalidDataContractException(string message, Type type)
168         {
169             DataContractCriticalHelper.ThrowInvalidDataContractException(message, type);
170         }
171
172 #if USE_REFEMIT
173         internal DataContractCriticalHelper Helper
174 #else
175         protected DataContractCriticalHelper Helper
176 #endif
177         {
178             [Fx.Tag.SecurityNote(Critical = "holds instance of CriticalHelper which keeps state that is cached statically for serialization."
179                 + " Static fields are marked SecurityCritical or readonly to prevent"
180                 + " data from being modified or leaked to other components in appdomain.")]
181             [SecurityCritical]
182             get { return helper; }
183         }
184
185         internal Type UnderlyingType
186         {
187             [Fx.Tag.SecurityNote(Critical = "Fetches the critical UnderlyingType field.",
188                 Safe = "Get-only properties only needs to be protected for write.")]
189             [SecuritySafeCritical]
190             get { return helper.UnderlyingType; }
191         }
192
193         internal Type OriginalUnderlyingType
194         {
195             [Fx.Tag.SecurityNote(Critical = "Fetches the critical OriginalUnderlyingType property.",
196                 Safe = "OrginalUnderlyingType only needs to be protected for write.")]
197             [SecuritySafeCritical]
198             get { return helper.OriginalUnderlyingType; }
199         }
200
201
202         internal virtual bool IsBuiltInDataContract
203         {
204             [Fx.Tag.SecurityNote(Critical = "Fetches the critical isBuiltInDataContract property.",
205                 Safe = "isBuiltInDataContract only needs to be protected for write.")]
206             [SecuritySafeCritical]
207             get { return helper.IsBuiltInDataContract; }
208         }
209
210         internal Type TypeForInitialization
211         {
212             [Fx.Tag.SecurityNote(Critical = "Fetches the critical typeForInitialization property.",
213                 Safe = "typeForInitialization only needs to be protected for write.")]
214             [SecuritySafeCritical]
215             get { return helper.TypeForInitialization; }
216         }
217
218         public virtual void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
219         {
220             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType))));
221         }
222
223         public virtual object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
224         {
225             throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType))));
226         }
227
228         internal bool IsValueType
229         {
230             [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsValueType property.",
231                 Safe = "IsValueType only needs to be protected for write.")]
232             [SecuritySafeCritical]
233             get { return helper.IsValueType; }
234             [Fx.Tag.SecurityNote(Critical = "Sets the critical IsValueType property.")]
235             [SecurityCritical]
236             set { helper.IsValueType = value; }
237         }
238
239         internal bool IsReference
240         {
241             [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsReference property.",
242                 Safe = "IsReference only needs to be protected for write.")]
243             [SecuritySafeCritical]
244             get { return helper.IsReference; }
245
246             [Fx.Tag.SecurityNote(Critical = "Sets the critical IsReference property.")]
247             [SecurityCritical]
248             set { helper.IsReference = value; }
249         }
250
251         internal XmlQualifiedName StableName
252         {
253             [Fx.Tag.SecurityNote(Critical = "Fetches the critical StableName property.",
254                 Safe = "StableName only needs to be protected for write.")]
255             [SecuritySafeCritical]
256             get { return helper.StableName; }
257
258             [Fx.Tag.SecurityNote(Critical = "Sets the critical StableName property.")]
259             [SecurityCritical]
260             set { helper.StableName = value; }
261         }
262
263         internal GenericInfo GenericInfo
264         {
265             [Fx.Tag.SecurityNote(Critical = "Fetches the critical GenericInfo property.",
266                 Safe = "GenericInfo only needs to be protected for write.")]
267             [SecuritySafeCritical]
268             get { return helper.GenericInfo; }
269             [Fx.Tag.SecurityNote(Critical = "Sets the critical GenericInfo property.",
270                 Safe = "Protected for write if contract has underlyingType .")]
271             [SecurityCritical]
272             set { helper.GenericInfo = value; }
273         }
274
275         internal virtual DataContractDictionary KnownDataContracts
276         {
277             [Fx.Tag.SecurityNote(Critical = "Fetches the critical KnownDataContracts property.",
278                 Safe = "KnownDataContracts only needs to be protected for write.")]
279             [SecuritySafeCritical]
280             get { return helper.KnownDataContracts; }
281
282             [Fx.Tag.SecurityNote(Critical = "Sets the critical KnownDataContracts property.")]
283             [SecurityCritical]
284             set { helper.KnownDataContracts = value; }
285         }
286
287         internal virtual bool IsISerializable
288         {
289             [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsISerializable property.",
290                 Safe = "IsISerializable only needs to be protected for write.")]
291             [SecuritySafeCritical]
292             get { return helper.IsISerializable; }
293
294             [Fx.Tag.SecurityNote(Critical = "Sets the critical IsISerializable property.")]
295             [SecurityCritical]
296             set { helper.IsISerializable = value; }
297         }
298
299         internal XmlDictionaryString Name
300         {
301             [Fx.Tag.SecurityNote(Critical = "Fetches the critical Name property.",
302                 Safe = "Name only needs to be protected for write.")]
303             [SecuritySafeCritical]
304             get { return this.name; }
305         }
306
307         public virtual XmlDictionaryString Namespace
308         {
309             [Fx.Tag.SecurityNote(Critical = "Fetches the critical Namespace property.",
310                 Safe = "Namespace only needs to be protected for write.")]
311             [SecuritySafeCritical]
312             get { return this.ns; }
313         }
314
315         internal virtual bool HasRoot
316         {
317             get { return true; }
318             set { }
319         }
320
321         internal virtual XmlDictionaryString TopLevelElementName
322         {
323             [Fx.Tag.SecurityNote(Critical = "Fetches the critical Name property.",
324                 Safe = "Name only needs to be protected for write.")]
325             [SecuritySafeCritical]
326             get { return helper.TopLevelElementName; }
327
328             [Fx.Tag.SecurityNote(Critical = "Sets the critical Name property.")]
329             [SecurityCritical]
330             set { helper.TopLevelElementName = value; }
331         }
332
333         internal virtual XmlDictionaryString TopLevelElementNamespace
334         {
335             [Fx.Tag.SecurityNote(Critical = "Fetches the critical Namespace property.",
336                 Safe = "Namespace only needs to be protected for write.")]
337             [SecuritySafeCritical]
338             get { return helper.TopLevelElementNamespace; }
339
340             [Fx.Tag.SecurityNote(Critical = "Sets the critical Namespace property.")]
341             [SecurityCritical]
342             set { helper.TopLevelElementNamespace = value; }
343         }
344
345         internal virtual bool CanContainReferences
346         {
347             get { return true; }
348         }
349
350         internal virtual bool IsPrimitive
351         {
352             get { return false; }
353         }
354
355         internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns)
356         {
357             if (object.ReferenceEquals(ns, DictionaryGlobals.SerializationNamespace) && !IsPrimitive)
358                 writer.WriteStartElement(Globals.SerPrefix, name, ns);
359             else
360                 writer.WriteStartElement(name, ns);
361         }
362
363         internal virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary<DataContract, DataContract> boundContracts)
364         {
365             return this;
366         }
367
368         internal virtual DataContract GetValidContract(SerializationMode mode)
369         {
370             return this;
371         }
372
373         internal virtual DataContract GetValidContract()
374         {
375             return this;
376         }
377
378         internal virtual bool IsValidContract(SerializationMode mode)
379         {
380             return true;
381         }
382
383         internal MethodInfo ParseMethod
384         {
385             [Fx.Tag.SecurityNote(Critical = "Fetches the critical ParseMethod field.",
386                 Safe = "Get-only properties only needs to be protected for write.")]
387             [SecuritySafeCritical]
388             get { return helper.ParseMethod; }
389         }
390
391         [Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing types."
392             + " Since the data is cached statically, we lock down access to it.")]
393 #if !NO_SECURITY_ATTRIBUTES
394         [SecurityCritical(SecurityCriticalScope.Everything)]
395 #endif
396 #if USE_REFEMIT
397         public class DataContractCriticalHelper
398 #else
399         protected class DataContractCriticalHelper
400 #endif
401         {
402             static Dictionary<TypeHandleRef, IntRef> typeToIDCache;
403             static DataContract[] dataContractCache;
404             static int dataContractID;
405             static Dictionary<Type, DataContract> typeToBuiltInContract;
406             static Dictionary<XmlQualifiedName, DataContract> nameToBuiltInContract;
407             static Dictionary<string, DataContract> typeNameToBuiltInContract;
408             static Dictionary<string, string> namespaces;
409             static Dictionary<string, XmlDictionaryString> clrTypeStrings;
410             static XmlDictionary clrTypeStringsDictionary;
411             static TypeHandleRef typeHandleRef = new TypeHandleRef();
412
413             static object cacheLock = new object();
414             static object createDataContractLock = new object();
415             static object initBuiltInContractsLock = new object();
416             static object namespacesLock = new object();
417             static object clrTypeStringsLock = new object();
418
419             readonly Type underlyingType;
420             Type originalUnderlyingType;
421             bool isReference;
422             bool isValueType;
423             XmlQualifiedName stableName;
424             GenericInfo genericInfo;
425             XmlDictionaryString name;
426             XmlDictionaryString ns;
427
428             [Fx.Tag.SecurityNote(Critical = "In deserialization, we initialize an object instance passing this Type to GetUninitializedObject method.")]
429             Type typeForInitialization;
430
431             MethodInfo parseMethod;
432             bool parseMethodSet;
433
434             static DataContractCriticalHelper()
435             {
436                 typeToIDCache = new Dictionary<TypeHandleRef, IntRef>(new TypeHandleRefEqualityComparer());
437                 dataContractCache = new DataContract[32];
438                 dataContractID = 0;
439             }
440
441             internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type)
442             {
443                 DataContract dataContract = dataContractCache[id];
444                 if (dataContract == null)
445                 {
446                     dataContract = CreateDataContract(id, typeHandle, type);
447                 }
448                 else
449                 {
450                     return dataContract.GetValidContract();
451                 }
452                 return dataContract;
453             }
454
455             internal static DataContract GetGetOnlyCollectionDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type)
456             {
457                 DataContract dataContract = dataContractCache[id];
458                 if (dataContract == null)
459                 {
460                     dataContract = CreateGetOnlyCollectionDataContract(id, typeHandle, type);
461                     dataContractCache[id] = dataContract;
462                 }
463                 return dataContract;
464             }
465
466             internal static DataContract GetDataContractForInitialization(int id)
467             {
468                 DataContract dataContract = dataContractCache[id];
469                 if (dataContract == null)
470                 {
471                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.DataContractCacheOverflow)));
472                 }
473                 return dataContract;
474             }
475
476             internal static int GetIdForInitialization(ClassDataContract classContract)
477             {
478                 int id = DataContract.GetId(classContract.TypeForInitialization.TypeHandle);
479                 if (id < dataContractCache.Length && ContractMatches(classContract, dataContractCache[id]))
480                 {
481                     return id;
482                 }
483                 for (int i = 0; i < DataContractCriticalHelper.dataContractID; i++)
484                 {
485                     if (ContractMatches(classContract, dataContractCache[i]))
486                     {
487                         return i;
488                     }
489                 }
490                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.DataContractCacheOverflow)));
491             }
492
493             static bool ContractMatches(DataContract contract, DataContract cachedContract)
494             {
495                 return (cachedContract != null && cachedContract.UnderlyingType == contract.UnderlyingType);
496             }
497
498             internal static int GetId(RuntimeTypeHandle typeHandle)
499             {
500                 lock (cacheLock)
501                 {
502                     IntRef id;
503                     typeHandle = GetDataContractAdapterTypeHandle(typeHandle);
504                     typeHandleRef.Value = typeHandle;
505                     if (!typeToIDCache.TryGetValue(typeHandleRef, out id))
506                     {
507                         id = GetNextId();
508                         try
509                         {
510                             typeToIDCache.Add(new TypeHandleRef(typeHandle), id);
511                         }
512                         catch (Exception ex)
513                         {
514                             if (Fx.IsFatal(ex))
515                             {
516                                 throw;
517                             }
518                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex);
519                         }
520                     }
521                     return id.Value;
522                 }
523             }
524
525             // Assumed that this method is called under a lock
526             static IntRef GetNextId()
527             {
528                 int value = dataContractID++;
529                 if (value >= dataContractCache.Length)
530                 {
531                     int newSize = (value < Int32.MaxValue / 2) ? value * 2 : Int32.MaxValue;
532                     if (newSize <= value)
533                     {
534                         Fx.Assert("DataContract cache overflow");
535                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.DataContractCacheOverflow)));
536                     }
537                     Array.Resize<DataContract>(ref dataContractCache, newSize);
538                 }
539                 return new IntRef(value);
540             }
541
542             // check whether a corresponding update is required in ClassDataContract.IsNonAttributedTypeValidForSerialization
543             static DataContract CreateDataContract(int id, RuntimeTypeHandle typeHandle, Type type)
544             {
545                 lock (createDataContractLock)
546                 {
547                     DataContract dataContract = dataContractCache[id];
548                     if (dataContract == null)
549                     {
550                         if (type == null)
551                             type = Type.GetTypeFromHandle(typeHandle);
552                         type = UnwrapNullableType(type);
553                         type = GetDataContractAdapterType(type);
554                         dataContract = GetBuiltInDataContract(type);
555                         if (dataContract == null)
556                         {
557                             if (type.IsArray)
558                                 dataContract = new CollectionDataContract(type);
559                             else if (type.IsEnum)
560                                 dataContract = new EnumDataContract(type);
561                             else if (type.IsGenericParameter)
562                                 dataContract = new GenericParameterDataContract(type);
563                             else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
564                                 dataContract = new XmlDataContract(type);
565                             else
566                             {
567                                 //if (type.ContainsGenericParameters)
568                                 //    ThrowInvalidDataContractException(SR.GetString(SR.TypeMustNotBeOpenGeneric, type), type);
569                                 if (type.IsPointer)
570                                     type = Globals.TypeOfReflectionPointer;
571
572                                 if (!CollectionDataContract.TryCreate(type, out dataContract))
573                                 {
574                                     if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type))
575                                     {
576                                         dataContract = new ClassDataContract(type);
577                                     }
578                                     else
579                                     {
580                                         ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type);
581                                     }
582                                 }
583                             }
584                         }
585                     }
586                     dataContractCache[id] = dataContract;
587                     return dataContract;
588                 }
589             }
590
591             static DataContract CreateGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type type)
592             {
593                 DataContract dataContract = null;
594                 lock (createDataContractLock)
595                 {
596                     dataContract = dataContractCache[id];
597                     if (dataContract == null)
598                     {
599                         if (type == null)
600                             type = Type.GetTypeFromHandle(typeHandle);
601                         type = UnwrapNullableType(type);
602                         type = GetDataContractAdapterType(type);
603                         if (!CollectionDataContract.TryCreateGetOnlyCollectionDataContract(type, out dataContract))
604                         {
605                             ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type);
606                         }
607                     }
608                 }
609                 return dataContract;
610             }
611
612             // Any change to this method should be reflected in GetDataContractOriginalType
613             internal static Type GetDataContractAdapterType(Type type)
614             {
615                 // Replace the DataTimeOffset ISerializable type passed in with the internal DateTimeOffsetAdapter DataContract type.
616                 // DateTimeOffsetAdapter is used for serialization/deserialization purposes to bypass the ISerializable implementation
617                 // on DateTimeOffset; which does not work in partial trust and to ensure correct schema import/export scenarios.
618                 if (type == Globals.TypeOfDateTimeOffset)
619                 {
620                     return Globals.TypeOfDateTimeOffsetAdapter;
621                 }
622                 return type;
623             }
624
625             // Maps adapted types back to the original type
626             // Any change to this method should be reflected in GetDataContractAdapterType
627             internal static Type GetDataContractOriginalType(Type type)
628             {
629                 if (type == Globals.TypeOfDateTimeOffsetAdapter)
630                 {
631                     return Globals.TypeOfDateTimeOffset;
632                 }
633                 return type;
634             }
635
636             static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHandle typeHandle)
637             {
638                 if (Globals.TypeOfDateTimeOffset.TypeHandle.Equals(typeHandle))
639                 {
640                     return Globals.TypeOfDateTimeOffsetAdapter.TypeHandle;
641                 }
642                 return typeHandle;
643             }
644
645             [SuppressMessage(FxCop.Category.Usage, "CA2301:EmbeddableTypesInContainersRule", MessageId = "typeToBuiltInContract", Justification = "No need to support type equivalence here.")]
646             public static DataContract GetBuiltInDataContract(Type type)
647             {
648                 if (type.IsInterface && !CollectionDataContract.IsCollectionInterface(type))
649                     type = Globals.TypeOfObject;
650
651                 lock (initBuiltInContractsLock)
652                 {
653                     if (typeToBuiltInContract == null)
654                         typeToBuiltInContract = new Dictionary<Type, DataContract>();
655
656                     DataContract dataContract = null;
657                     if (!typeToBuiltInContract.TryGetValue(type, out dataContract))
658                     {
659                         TryCreateBuiltInDataContract(type, out dataContract);
660                         typeToBuiltInContract.Add(type, dataContract);
661                     }
662                     return dataContract;
663                 }
664             }
665
666             public static DataContract GetBuiltInDataContract(string name, string ns)
667             {
668                 lock (initBuiltInContractsLock)
669                 {
670                     if (nameToBuiltInContract == null)
671                         nameToBuiltInContract = new Dictionary<XmlQualifiedName, DataContract>();
672
673                     DataContract dataContract = null;
674                     XmlQualifiedName qname = new XmlQualifiedName(name, ns);
675                     if (!nameToBuiltInContract.TryGetValue(qname, out dataContract))
676                     {
677                         if (TryCreateBuiltInDataContract(name, ns, out dataContract))
678                         {
679                             nameToBuiltInContract.Add(qname, dataContract);
680                         }
681                     }
682                     return dataContract;
683                 }
684             }
685
686             public static DataContract GetBuiltInDataContract(string typeName)
687             {
688                 if (!typeName.StartsWith("System.", StringComparison.Ordinal))
689                     return null;
690
691                 lock (initBuiltInContractsLock)
692                 {
693                     if (typeNameToBuiltInContract == null)
694                         typeNameToBuiltInContract = new Dictionary<string, DataContract>();
695
696                     DataContract dataContract = null;
697                     if (!typeNameToBuiltInContract.TryGetValue(typeName, out dataContract))
698                     {
699                         Type type = null;
700                         string name = typeName.Substring(7);
701                         if (name == "Char")
702                             type = typeof(Char);
703                         else if (name == "Boolean")
704                             type = typeof(Boolean);
705                         else if (name == "SByte")
706                             type = typeof(SByte);
707                         else if (name == "Byte")
708                             type = typeof(Byte);
709                         else if (name == "Int16")
710                             type = typeof(Int16);
711                         else if (name == "UInt16")
712                             type = typeof(UInt16);
713                         else if (name == "Int32")
714                             type = typeof(Int32);
715                         else if (name == "UInt32")
716                             type = typeof(UInt32);
717                         else if (name == "Int64")
718                             type = typeof(Int64);
719                         else if (name == "UInt64")
720                             type = typeof(UInt64);
721                         else if (name == "Single")
722                             type = typeof(Single);
723                         else if (name == "Double")
724                             type = typeof(Double);
725                         else if (name == "Decimal")
726                             type = typeof(Decimal);
727                         else if (name == "DateTime")
728                             type = typeof(DateTime);
729                         else if (name == "String")
730                             type = typeof(String);
731                         else if (name == "Byte[]")
732                             type = typeof(byte[]);
733                         else if (name == "Object")
734                             type = typeof(Object);
735                         else if (name == "TimeSpan")
736                             type = typeof(TimeSpan);
737                         else if (name == "Guid")
738                             type = typeof(Guid);
739                         else if (name == "Uri")
740                             type = typeof(Uri);
741                         else if (name == "Xml.XmlQualifiedName")
742                             type = typeof(XmlQualifiedName);
743                         else if (name == "Enum")
744                             type = typeof(Enum);
745                         else if (name == "ValueType")
746                             type = typeof(ValueType);
747                         else if (name == "Array")
748                             type = typeof(Array);
749                         else if (name == "Xml.XmlElement")
750                             type = typeof(XmlElement);
751                         else if (name == "Xml.XmlNode[]")
752                             type = typeof(XmlNode[]);
753
754                         if (type != null)
755                             TryCreateBuiltInDataContract(type, out dataContract);
756
757                         typeNameToBuiltInContract.Add(typeName, dataContract);
758                     }
759                     return dataContract;
760                 }
761             }
762
763             static public bool TryCreateBuiltInDataContract(Type type, out DataContract dataContract)
764             {
765                 if (type.IsEnum) // Type.GetTypeCode will report Enums as TypeCode.IntXX
766                 {
767                     dataContract = null;
768                     return false;
769                 }
770                 dataContract = null;
771                 switch (Type.GetTypeCode(type))
772                 {
773                     case TypeCode.Boolean:
774                         dataContract = new BooleanDataContract();
775                         break;
776                     case TypeCode.Byte:
777                         dataContract = new UnsignedByteDataContract();
778                         break;
779                     case TypeCode.Char:
780                         dataContract = new CharDataContract();
781                         break;
782                     case TypeCode.DateTime:
783                         dataContract = new DateTimeDataContract();
784                         break;
785                     case TypeCode.Decimal:
786                         dataContract = new DecimalDataContract();
787                         break;
788                     case TypeCode.Double:
789                         dataContract = new DoubleDataContract();
790                         break;
791                     case TypeCode.Int16:
792                         dataContract = new ShortDataContract();
793                         break;
794                     case TypeCode.Int32:
795                         dataContract = new IntDataContract();
796                         break;
797                     case TypeCode.Int64:
798                         dataContract = new LongDataContract();
799                         break;
800                     case TypeCode.SByte:
801                         dataContract = new SignedByteDataContract();
802                         break;
803                     case TypeCode.Single:
804                         dataContract = new FloatDataContract();
805                         break;
806                     case TypeCode.String:
807                         dataContract = new StringDataContract();
808                         break;
809                     case TypeCode.UInt16:
810                         dataContract = new UnsignedShortDataContract();
811                         break;
812                     case TypeCode.UInt32:
813                         dataContract = new UnsignedIntDataContract();
814                         break;
815                     case TypeCode.UInt64:
816                         dataContract = new UnsignedLongDataContract();
817                         break;
818                     default:
819                         if (type == typeof(byte[]))
820                             dataContract = new ByteArrayDataContract();
821                         else if (type == typeof(object))
822                             dataContract = new ObjectDataContract();
823                         else if (type == typeof(Uri))
824                             dataContract = new UriDataContract();
825                         else if (type == typeof(XmlQualifiedName))
826                             dataContract = new QNameDataContract();
827                         else if (type == typeof(TimeSpan))
828                             dataContract = new TimeSpanDataContract();
829                         else if (type == typeof(Guid))
830                             dataContract = new GuidDataContract();
831                         else if (type == typeof(Enum) || type == typeof(ValueType))
832                         {
833                             dataContract = new SpecialTypeDataContract(type, DictionaryGlobals.ObjectLocalName, DictionaryGlobals.SchemaNamespace);
834                         }
835                         else if (type == typeof(Array))
836                             dataContract = new CollectionDataContract(type);
837                         else if (type == typeof(XmlElement) || type == typeof(XmlNode[]))
838                             dataContract = new XmlDataContract(type);
839                         break;
840                 }
841                 return dataContract != null;
842             }
843
844             static public bool TryCreateBuiltInDataContract(string name, string ns, out DataContract dataContract)
845             {
846                 dataContract = null;
847                 if (ns == DictionaryGlobals.SchemaNamespace.Value)
848                 {
849                     if (DictionaryGlobals.BooleanLocalName.Value == name)
850                         dataContract = new BooleanDataContract();
851                     else if (DictionaryGlobals.SignedByteLocalName.Value == name)
852                         dataContract = new SignedByteDataContract();
853                     else if (DictionaryGlobals.UnsignedByteLocalName.Value == name)
854                         dataContract = new UnsignedByteDataContract();
855                     else if (DictionaryGlobals.ShortLocalName.Value == name)
856                         dataContract = new ShortDataContract();
857                     else if (DictionaryGlobals.UnsignedShortLocalName.Value == name)
858                         dataContract = new UnsignedShortDataContract();
859                     else if (DictionaryGlobals.IntLocalName.Value == name)
860                         dataContract = new IntDataContract();
861                     else if (DictionaryGlobals.UnsignedIntLocalName.Value == name)
862                         dataContract = new UnsignedIntDataContract();
863                     else if (DictionaryGlobals.LongLocalName.Value == name)
864                         dataContract = new LongDataContract();
865                     else if (DictionaryGlobals.integerLocalName.Value == name)
866                         dataContract = new IntegerDataContract();
867                     else if (DictionaryGlobals.positiveIntegerLocalName.Value == name)
868                         dataContract = new PositiveIntegerDataContract();
869                     else if (DictionaryGlobals.negativeIntegerLocalName.Value == name)
870                         dataContract = new NegativeIntegerDataContract();
871                     else if (DictionaryGlobals.nonPositiveIntegerLocalName.Value == name)
872                         dataContract = new NonPositiveIntegerDataContract();
873                     else if (DictionaryGlobals.nonNegativeIntegerLocalName.Value == name)
874                         dataContract = new NonNegativeIntegerDataContract();
875                     else if (DictionaryGlobals.UnsignedLongLocalName.Value == name)
876                         dataContract = new UnsignedLongDataContract();
877                     else if (DictionaryGlobals.FloatLocalName.Value == name)
878                         dataContract = new FloatDataContract();
879                     else if (DictionaryGlobals.DoubleLocalName.Value == name)
880                         dataContract = new DoubleDataContract();
881                     else if (DictionaryGlobals.DecimalLocalName.Value == name)
882                         dataContract = new DecimalDataContract();
883                     else if (DictionaryGlobals.DateTimeLocalName.Value == name)
884                         dataContract = new DateTimeDataContract();
885                     else if (DictionaryGlobals.StringLocalName.Value == name)
886                         dataContract = new StringDataContract();
887                     else if (DictionaryGlobals.timeLocalName.Value == name)
888                         dataContract = new TimeDataContract();
889                     else if (DictionaryGlobals.dateLocalName.Value == name)
890                         dataContract = new DateDataContract();
891                     else if (DictionaryGlobals.hexBinaryLocalName.Value == name)
892                         dataContract = new HexBinaryDataContract();
893                     else if (DictionaryGlobals.gYearMonthLocalName.Value == name)
894                         dataContract = new GYearMonthDataContract();
895                     else if (DictionaryGlobals.gYearLocalName.Value == name)
896                         dataContract = new GYearDataContract();
897                     else if (DictionaryGlobals.gMonthDayLocalName.Value == name)
898                         dataContract = new GMonthDayDataContract();
899                     else if (DictionaryGlobals.gDayLocalName.Value == name)
900                         dataContract = new GDayDataContract();
901                     else if (DictionaryGlobals.gMonthLocalName.Value == name)
902                         dataContract = new GMonthDataContract();
903                     else if (DictionaryGlobals.normalizedStringLocalName.Value == name)
904                         dataContract = new NormalizedStringDataContract();
905                     else if (DictionaryGlobals.tokenLocalName.Value == name)
906                         dataContract = new TokenDataContract();
907                     else if (DictionaryGlobals.languageLocalName.Value == name)
908                         dataContract = new LanguageDataContract();
909                     else if (DictionaryGlobals.NameLocalName.Value == name)
910                         dataContract = new NameDataContract();
911                     else if (DictionaryGlobals.NCNameLocalName.Value == name)
912                         dataContract = new NCNameDataContract();
913                     else if (DictionaryGlobals.XSDIDLocalName.Value == name)
914                         dataContract = new IDDataContract();
915                     else if (DictionaryGlobals.IDREFLocalName.Value == name)
916                         dataContract = new IDREFDataContract();
917                     else if (DictionaryGlobals.IDREFSLocalName.Value == name)
918                         dataContract = new IDREFSDataContract();
919                     else if (DictionaryGlobals.ENTITYLocalName.Value == name)
920                         dataContract = new ENTITYDataContract();
921                     else if (DictionaryGlobals.ENTITIESLocalName.Value == name)
922                         dataContract = new ENTITIESDataContract();
923                     else if (DictionaryGlobals.NMTOKENLocalName.Value == name)
924                         dataContract = new NMTOKENDataContract();
925                     else if (DictionaryGlobals.NMTOKENSLocalName.Value == name)
926                         dataContract = new NMTOKENDataContract();
927                     else if (DictionaryGlobals.ByteArrayLocalName.Value == name)
928                         dataContract = new ByteArrayDataContract();
929                     else if (DictionaryGlobals.ObjectLocalName.Value == name)
930                         dataContract = new ObjectDataContract();
931                     else if (DictionaryGlobals.TimeSpanLocalName.Value == name)
932                         dataContract = new XsDurationDataContract();
933                     else if (DictionaryGlobals.UriLocalName.Value == name)
934                         dataContract = new UriDataContract();
935                     else if (DictionaryGlobals.QNameLocalName.Value == name)
936                         dataContract = new QNameDataContract();
937                 }
938                 else if (ns == DictionaryGlobals.SerializationNamespace.Value)
939                 {
940                     if (DictionaryGlobals.TimeSpanLocalName.Value == name)
941                         dataContract = new TimeSpanDataContract();
942                     else if (DictionaryGlobals.GuidLocalName.Value == name)
943                         dataContract = new GuidDataContract();
944                     else if (DictionaryGlobals.CharLocalName.Value == name)
945                         dataContract = new CharDataContract();
946                     else if ("ArrayOfanyType" == name)
947                         dataContract = new CollectionDataContract(typeof(Array));
948                 }
949                 else if (ns == DictionaryGlobals.AsmxTypesNamespace.Value)
950                 {
951                     if (DictionaryGlobals.CharLocalName.Value == name)
952                         dataContract = new AsmxCharDataContract();
953                     else if (DictionaryGlobals.GuidLocalName.Value == name)
954                         dataContract = new AsmxGuidDataContract();
955                 }
956                 else if (ns == Globals.DataContractXmlNamespace)
957                 {
958                     if (name == "XmlElement")
959                         dataContract = new XmlDataContract(typeof(XmlElement));
960                     else if (name == "ArrayOfXmlNode")
961                         dataContract = new XmlDataContract(typeof(XmlNode[]));
962                 }
963                 return dataContract != null;
964             }
965
966             internal static string GetNamespace(string key)
967             {
968                 lock (namespacesLock)
969                 {
970                     if (namespaces == null)
971                         namespaces = new Dictionary<string, string>();
972                     string value;
973                     if (namespaces.TryGetValue(key, out value))
974                         return value;
975                     try
976                     {
977                         namespaces.Add(key, key);
978                     }
979                     catch (Exception ex)
980                     {
981                         if (Fx.IsFatal(ex))
982                         {
983                             throw;
984                         }
985                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex);
986                     }
987                     return key;
988                 }
989             }
990
991             internal static XmlDictionaryString GetClrTypeString(string key)
992             {
993                 lock (clrTypeStringsLock)
994                 {
995                     if (clrTypeStrings == null)
996                     {
997                         clrTypeStringsDictionary = new XmlDictionary();
998                         clrTypeStrings = new Dictionary<string, XmlDictionaryString>();
999                         try
1000                         {
1001                             clrTypeStrings.Add(Globals.TypeOfInt.Assembly.FullName, clrTypeStringsDictionary.Add(Globals.MscorlibAssemblyName));
1002                         }
1003                         catch (Exception ex)
1004                         {
1005                             if (Fx.IsFatal(ex))
1006                             {
1007                                 throw;
1008                             }
1009                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex);
1010                         }
1011                     }
1012                     XmlDictionaryString value;
1013                     if (clrTypeStrings.TryGetValue(key, out value))
1014                         return value;
1015                     value = clrTypeStringsDictionary.Add(key);
1016                     try
1017                     {
1018                         clrTypeStrings.Add(key, value);
1019                     }
1020                     catch (Exception ex)
1021                     {
1022                         if (Fx.IsFatal(ex))
1023                         {
1024                             throw;
1025                         }
1026                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex);
1027                     }
1028                     return value;
1029                 }
1030             }
1031
1032             internal static void ThrowInvalidDataContractException(string message, Type type)
1033             {
1034                 if (type != null)
1035                 {
1036                     lock (cacheLock)
1037                     {
1038                         typeHandleRef.Value = GetDataContractAdapterTypeHandle(type.TypeHandle);
1039                         try
1040                         {
1041                             typeToIDCache.Remove(typeHandleRef);
1042                         }
1043                         catch (Exception ex)
1044                         {
1045                             if (Fx.IsFatal(ex))
1046                             {
1047                                 throw;
1048                             }
1049                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex);
1050                         }
1051                     }
1052                 }
1053
1054                 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(message));
1055             }
1056
1057             internal DataContractCriticalHelper()
1058             {
1059             }
1060
1061             internal DataContractCriticalHelper(Type type)
1062             {
1063                 underlyingType = type;
1064                 SetTypeForInitialization(type);
1065                 isValueType = type.IsValueType;
1066             }
1067
1068             internal Type UnderlyingType
1069             {
1070                 get { return underlyingType; }
1071             }
1072
1073             internal Type OriginalUnderlyingType
1074             {
1075                 get
1076                 {
1077                     if (this.originalUnderlyingType == null)
1078                     {
1079                         this.originalUnderlyingType = GetDataContractOriginalType(this.underlyingType);
1080                     }
1081                     return this.originalUnderlyingType;
1082                 }
1083             }
1084
1085             internal virtual bool IsBuiltInDataContract
1086             {
1087                 get
1088                 {
1089                     return false;
1090                 }
1091             }
1092
1093             internal Type TypeForInitialization
1094             {
1095                 get { return this.typeForInitialization; }
1096             }
1097
1098             [Fx.Tag.SecurityNote(Critical = "Sets the critical typeForInitialization property.",
1099                 Safe = "Validates input data, sets field correctly.")]
1100             [SecuritySafeCritical]
1101             void SetTypeForInitialization(Type classType)
1102             {
1103                 if (classType.IsSerializable || classType.IsDefined(Globals.TypeOfDataContractAttribute, false))
1104                 {
1105                     this.typeForInitialization = classType;
1106                 }
1107             }
1108
1109             internal bool IsReference
1110             {
1111                 get { return isReference; }
1112                 set
1113                 {
1114                     isReference = value;
1115                 }
1116             }
1117
1118             internal bool IsValueType
1119             {
1120                 get { return isValueType; }
1121                 set { isValueType = value; }
1122             }
1123
1124             internal XmlQualifiedName StableName
1125             {
1126                 get { return stableName; }
1127                 set { stableName = value; }
1128             }
1129
1130             internal GenericInfo GenericInfo
1131             {
1132                 get { return genericInfo; }
1133                 set { genericInfo = value; }
1134             }
1135
1136             internal virtual DataContractDictionary KnownDataContracts
1137             {
1138                 get { return null; }
1139                 set { /* do nothing */ }
1140             }
1141
1142             internal virtual bool IsISerializable
1143             {
1144                 get { return false; }
1145                 set { ThrowInvalidDataContractException(SR.GetString(SR.RequiresClassDataContractToSetIsISerializable)); }
1146             }
1147
1148             internal XmlDictionaryString Name
1149             {
1150                 get { return name; }
1151                 set { name = value; }
1152             }
1153
1154             public XmlDictionaryString Namespace
1155             {
1156                 get { return ns; }
1157                 set { ns = value; }
1158             }
1159
1160             internal virtual bool HasRoot
1161             {
1162                 get { return true; }
1163                 set { }
1164             }
1165
1166             internal virtual XmlDictionaryString TopLevelElementName
1167             {
1168                 get { return name; }
1169                 set { name = value; }
1170             }
1171
1172             internal virtual XmlDictionaryString TopLevelElementNamespace
1173             {
1174                 get { return ns; }
1175                 set { ns = value; }
1176             }
1177
1178             internal virtual bool CanContainReferences
1179             {
1180                 get { return true; }
1181             }
1182
1183             internal virtual bool IsPrimitive
1184             {
1185                 get { return false; }
1186             }
1187
1188             internal MethodInfo ParseMethod
1189             {
1190                 get 
1191                 {
1192                     if (!parseMethodSet)
1193                     {
1194                         MethodInfo method = UnderlyingType.GetMethod(Globals.ParseMethodName, BindingFlags.Public | BindingFlags.Static, null, new Type[] { Globals.TypeOfString }, null);
1195
1196                         if (method != null && method.ReturnType == UnderlyingType)
1197                         {
1198                             parseMethod = method;
1199                         }
1200
1201                         parseMethodSet = true;
1202                     }
1203                     return parseMethod; }
1204             }
1205
1206             internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns)
1207             {
1208                 if (object.ReferenceEquals(ns, DictionaryGlobals.SerializationNamespace) && !IsPrimitive)
1209                     writer.WriteStartElement(Globals.SerPrefix, name, ns);
1210                 else
1211                     writer.WriteStartElement(name, ns);
1212             }
1213
1214             internal void SetDataContractName(XmlQualifiedName stableName)
1215             {
1216                 XmlDictionary dictionary = new XmlDictionary(2);
1217                 this.Name = dictionary.Add(stableName.Name);
1218                 this.Namespace = dictionary.Add(stableName.Namespace);
1219                 this.StableName = stableName;
1220             }
1221
1222             internal void SetDataContractName(XmlDictionaryString name, XmlDictionaryString ns)
1223             {
1224                 this.Name = name;
1225                 this.Namespace = ns;
1226                 this.StableName = CreateQualifiedName(name.Value, ns.Value);
1227             }
1228
1229             internal void ThrowInvalidDataContractException(string message)
1230             {
1231                 ThrowInvalidDataContractException(message, UnderlyingType);
1232             }
1233         }
1234
1235         static internal bool IsTypeSerializable(Type type)
1236         {
1237             return IsTypeSerializable(type, new Dictionary<Type, object>());
1238         }
1239
1240         static bool IsTypeSerializable(Type type, Dictionary<Type, object> previousCollectionTypes)
1241         {
1242             Type itemType;
1243             if (type.IsSerializable ||
1244                 type.IsDefined(Globals.TypeOfDataContractAttribute, false) ||
1245                 type.IsInterface ||
1246                 type.IsPointer ||
1247                 Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
1248             {
1249                 return true;
1250             }
1251             if (CollectionDataContract.IsCollection(type, out itemType))
1252             {
1253                 ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes);
1254                 if (IsTypeSerializable(itemType, previousCollectionTypes))
1255                 {
1256                     return true;
1257                 }
1258             }
1259             return (DataContract.GetBuiltInDataContract(type) != null || ClassDataContract.IsNonAttributedTypeValidForSerialization(type));
1260         }
1261
1262         [SuppressMessage(FxCop.Category.Usage, "CA2301:EmbeddableTypesInContainersRule", MessageId = "previousCollectionTypes", Justification = "No need to support type equivalence here.")]
1263         static void ValidatePreviousCollectionTypes(Type collectionType, Type itemType, Dictionary<Type, object> previousCollectionTypes)
1264         {
1265             previousCollectionTypes.Add(collectionType, collectionType);
1266             while (itemType.IsArray)
1267             {
1268                 itemType = itemType.GetElementType();
1269             }
1270
1271             // Do a breadth first traversal of the generic type tree to 
1272             // produce the closure of all generic argument types and
1273             // check that none of these is in the previousCollectionTypes            
1274             
1275             List<Type> itemTypeClosure = new List<Type>();
1276             Queue<Type> itemTypeQueue = new Queue<Type>();
1277
1278             itemTypeQueue.Enqueue(itemType);
1279             itemTypeClosure.Add(itemType);
1280                        
1281             while (itemTypeQueue.Count > 0)
1282             {
1283                 itemType = itemTypeQueue.Dequeue();
1284                 if (previousCollectionTypes.ContainsKey(itemType))
1285                 {
1286                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.RecursiveCollectionType, DataContract.GetClrTypeFullName(itemType))));
1287                 }
1288                 if (itemType.IsGenericType)
1289                 {
1290                     foreach (Type argType in itemType.GetGenericArguments())
1291                     {
1292                         if (!itemTypeClosure.Contains(argType))
1293                         {
1294                             itemTypeQueue.Enqueue(argType);
1295                             itemTypeClosure.Add(argType);
1296                         }
1297                     }
1298                 }
1299             }
1300         }
1301
1302         internal static Type UnwrapRedundantNullableType(Type type)
1303         {
1304             Type nullableType = type;
1305             while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
1306             {
1307                 nullableType = type;
1308                 type = type.GetGenericArguments()[0];
1309             }
1310             return nullableType;
1311         }
1312
1313         internal static Type UnwrapNullableType(Type type)
1314         {
1315             while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
1316                 type = type.GetGenericArguments()[0];
1317             return type;
1318         }
1319
1320         static bool IsAlpha(char ch)
1321         {
1322             return (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z');
1323         }
1324
1325         static bool IsDigit(char ch)
1326         {
1327             return (ch >= '0' && ch <= '9');
1328         }
1329
1330         static bool IsAsciiLocalName(string localName)
1331         {
1332             if (localName.Length == 0)
1333                 return false;
1334             if (!IsAlpha(localName[0]))
1335                 return false;
1336             for (int i = 1; i < localName.Length; i++)
1337             {
1338                 char ch = localName[i];
1339                 if (!IsAlpha(ch) && !IsDigit(ch))
1340                     return false;
1341             }
1342             return true;
1343         }
1344
1345         static internal string EncodeLocalName(string localName)
1346         {
1347             if (IsAsciiLocalName(localName))
1348                 return localName;
1349
1350             if (IsValidNCName(localName))
1351                 return localName;
1352
1353             return XmlConvert.EncodeLocalName(localName);
1354         }
1355
1356         internal static bool IsValidNCName(string name)
1357         {
1358             try
1359             {
1360                 XmlConvert.VerifyNCName(name);
1361                 return true;
1362             }
1363             catch (XmlException)
1364             {
1365                 return false;
1366             }
1367         }
1368
1369         internal static XmlQualifiedName GetStableName(Type type)
1370         {
1371             bool hasDataContract;
1372             return GetStableName(type, out hasDataContract);
1373         }
1374
1375         internal static XmlQualifiedName GetStableName(Type type, out bool hasDataContract)
1376         {
1377             return GetStableName(type, new Dictionary<Type, object>(), out hasDataContract);
1378         }
1379
1380         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Callers may need to depend on hasDataContract for a security decision."
1381             + " hasDataContract must be calculated correctly."
1382             + " GetStableName is factored into sub-methods so as to isolate the DataContractAttribute calculation and reduce SecurityCritical surface area.",
1383             Safe = "Does not let caller influence hasDataContract calculation; no harm in leaking value.")]
1384         static XmlQualifiedName GetStableName(Type type, Dictionary<Type, object> previousCollectionTypes, out bool hasDataContract)
1385         {
1386             type = UnwrapRedundantNullableType(type);
1387             XmlQualifiedName stableName;
1388             if (TryGetBuiltInXmlAndArrayTypeStableName(type, previousCollectionTypes, out stableName))
1389             {
1390                 hasDataContract = false;
1391             }
1392             else
1393             {
1394                 DataContractAttribute dataContractAttribute;
1395                 if (TryGetDCAttribute(type, out dataContractAttribute))
1396                 {
1397                     stableName = GetDCTypeStableName(type, dataContractAttribute);
1398                     hasDataContract = true;
1399                 }
1400                 else
1401                 {
1402                     stableName = GetNonDCTypeStableName(type, previousCollectionTypes);
1403                     hasDataContract = false;
1404                 }
1405             }
1406
1407             return stableName;
1408         }
1409
1410         static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttribute dataContractAttribute)
1411         {
1412             string name = null, ns = null;
1413             if (dataContractAttribute.IsNameSetExplicitly)
1414             {
1415                 name = dataContractAttribute.Name;
1416                 if (name == null || name.Length == 0)
1417                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidDataContractName, DataContract.GetClrTypeFullName(type))));
1418                 if (type.IsGenericType && !type.IsGenericTypeDefinition)
1419                     name = ExpandGenericParameters(name, type);
1420                 name = DataContract.EncodeLocalName(name);
1421             }
1422             else
1423                 name = GetDefaultStableLocalName(type);
1424
1425             if (dataContractAttribute.IsNamespaceSetExplicitly)
1426             {
1427                 ns = dataContractAttribute.Namespace;
1428                 if (ns == null)
1429                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidDataContractNamespace, DataContract.GetClrTypeFullName(type))));
1430                 CheckExplicitDataContractNamespaceUri(ns, type);
1431             }
1432             else
1433                 ns = GetDefaultDataContractNamespace(type);
1434
1435             return CreateQualifiedName(name, ns);
1436         }
1437
1438         static XmlQualifiedName GetNonDCTypeStableName(Type type, Dictionary<Type, object> previousCollectionTypes)
1439         {
1440             string name = null, ns = null;
1441
1442             Type itemType;
1443             CollectionDataContractAttribute collectionContractAttribute;
1444             if (CollectionDataContract.IsCollection(type, out itemType))
1445             {
1446                 ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes);
1447                 return GetCollectionStableName(type, itemType, previousCollectionTypes, out collectionContractAttribute);
1448             }
1449             name = GetDefaultStableLocalName(type);
1450
1451             // ensures that ContractNamespaceAttribute is honored when used with non-attributed types
1452             if (ClassDataContract.IsNonAttributedTypeValidForSerialization(type))
1453             {
1454                 ns = GetDefaultDataContractNamespace(type);
1455             }
1456             else
1457             {
1458                 ns = GetDefaultStableNamespace(type);
1459             }
1460             return CreateQualifiedName(name, ns);
1461         }
1462
1463         static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, Dictionary<Type, object> previousCollectionTypes, out XmlQualifiedName stableName)
1464         {
1465             stableName = null;
1466
1467             DataContract builtInContract = GetBuiltInDataContract(type);
1468             if (builtInContract != null)
1469             {
1470                 stableName = builtInContract.StableName;
1471             }
1472             else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
1473             {
1474                 bool hasRoot;
1475                 XmlSchemaType xsdType;
1476                 XmlQualifiedName xmlTypeStableName;
1477                 SchemaExporter.GetXmlTypeInfo(type, out xmlTypeStableName, out xsdType, out hasRoot);
1478                 stableName = xmlTypeStableName;
1479             }
1480             else if (type.IsArray)
1481             {
1482                 Type itemType = type.GetElementType();
1483                 ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes);
1484                 CollectionDataContractAttribute collectionContractAttribute;
1485                 stableName = GetCollectionStableName(type, itemType, previousCollectionTypes, out collectionContractAttribute);
1486             }
1487             return stableName != null;
1488         }
1489
1490         [Fx.Tag.SecurityNote(Critical = "Marked SecurityCritical because callers may need to base security decisions on the presence (or absence) of the DC attribute.",
1491             Safe = "Does not let caller influence calculation and the result is not a protected value.")]
1492         [SecuritySafeCritical]
1493         internal static bool TryGetDCAttribute(Type type, out DataContractAttribute dataContractAttribute)
1494         {
1495             dataContractAttribute = null;
1496
1497             object[] dataContractAttributes = type.GetCustomAttributes(Globals.TypeOfDataContractAttribute, false);
1498             if (dataContractAttributes != null && dataContractAttributes.Length > 0)
1499             {
1500 #if DEBUG
1501                 if (dataContractAttributes.Length > 1)
1502                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.TooManyDataContracts, DataContract.GetClrTypeFullName(type))));
1503 #endif
1504                 dataContractAttribute = (DataContractAttribute)dataContractAttributes[0];
1505             }
1506
1507             return dataContractAttribute != null;
1508         }
1509
1510         internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, out CollectionDataContractAttribute collectionContractAttribute)
1511         {
1512             return GetCollectionStableName(type, itemType, new Dictionary<Type, object>(), out collectionContractAttribute);
1513         }
1514
1515         static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, Dictionary<Type, object> previousCollectionTypes, out CollectionDataContractAttribute collectionContractAttribute)
1516         {
1517             string name, ns;
1518             object[] collectionContractAttributes = type.GetCustomAttributes(Globals.TypeOfCollectionDataContractAttribute, false);
1519             if (collectionContractAttributes != null && collectionContractAttributes.Length > 0)
1520             {
1521 #if DEBUG
1522                 if (collectionContractAttributes.Length > 1)
1523                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.TooManyCollectionContracts, DataContract.GetClrTypeFullName(type))));
1524 #endif
1525                 collectionContractAttribute = (CollectionDataContractAttribute)collectionContractAttributes[0];
1526                 if (collectionContractAttribute.IsNameSetExplicitly)
1527                 {
1528                     name = collectionContractAttribute.Name;
1529                     if (name == null || name.Length == 0)
1530                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractName, DataContract.GetClrTypeFullName(type))));
1531                     if (type.IsGenericType && !type.IsGenericTypeDefinition)
1532                         name = ExpandGenericParameters(name, type);
1533                     name = DataContract.EncodeLocalName(name);
1534                 }
1535                 else
1536                     name = GetDefaultStableLocalName(type);
1537
1538                 if (collectionContractAttribute.IsNamespaceSetExplicitly)
1539                 {
1540                     ns = collectionContractAttribute.Namespace;
1541                     if (ns == null)
1542                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractNamespace, DataContract.GetClrTypeFullName(type))));
1543                     CheckExplicitDataContractNamespaceUri(ns, type);
1544                 }
1545                 else
1546                     ns = GetDefaultDataContractNamespace(type);
1547             }
1548             else
1549             {
1550                 collectionContractAttribute = null;
1551                 string arrayOfPrefix = Globals.ArrayPrefix + GetArrayPrefix(ref itemType);
1552                 bool hasDataContract;
1553                 XmlQualifiedName elementStableName = GetStableName(itemType, previousCollectionTypes, out hasDataContract);
1554                 name = arrayOfPrefix + elementStableName.Name;
1555                 ns = GetCollectionNamespace(elementStableName.Namespace);
1556             }
1557             return CreateQualifiedName(name, ns);
1558         }
1559
1560         private static string GetArrayPrefix(ref Type itemType)
1561         {
1562             string arrayOfPrefix = string.Empty;
1563             while (itemType.IsArray)
1564             {
1565                 if (DataContract.GetBuiltInDataContract(itemType) != null)
1566                     break;
1567                 arrayOfPrefix += Globals.ArrayPrefix;
1568                 itemType = itemType.GetElementType();
1569             }
1570             return arrayOfPrefix;
1571         }
1572
1573         internal XmlQualifiedName GetArrayTypeName(bool isNullable)
1574         {
1575             XmlQualifiedName itemName;
1576             if (this.IsValueType && isNullable)
1577             {
1578                 GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName);
1579                 genericInfo.Add(new GenericInfo(this.StableName, null));
1580                 genericInfo.AddToLevel(0, 1);
1581                 itemName = genericInfo.GetExpandedStableName();
1582             }
1583             else
1584                 itemName = this.StableName;
1585             string ns = GetCollectionNamespace(itemName.Namespace);
1586             string name = Globals.ArrayPrefix + itemName.Name;
1587             return new XmlQualifiedName(name, ns);
1588         }
1589
1590         internal static string GetCollectionNamespace(string elementNs)
1591         {
1592             return IsBuiltInNamespace(elementNs) ? Globals.CollectionsNamespace : elementNs;
1593         }
1594
1595         internal static XmlQualifiedName GetDefaultStableName(Type type)
1596         {
1597             return CreateQualifiedName(GetDefaultStableLocalName(type), GetDefaultStableNamespace(type));
1598         }
1599
1600         static string GetDefaultStableLocalName(Type type)
1601         {
1602             if (type.IsGenericParameter)
1603                 return "{" + type.GenericParameterPosition + "}";
1604             string typeName;
1605             string arrayPrefix = null;
1606             if (type.IsArray)
1607                 arrayPrefix = GetArrayPrefix(ref type);
1608             if (type.DeclaringType == null)
1609                 typeName = type.Name;
1610             else
1611             {
1612                 int nsLen = (type.Namespace == null) ? 0 : type.Namespace.Length;
1613                 if (nsLen > 0)
1614                     nsLen++; //include the . following namespace
1615                 typeName = DataContract.GetClrTypeFullName(type).Substring(nsLen).Replace('+', '.');
1616             }
1617             if (arrayPrefix != null)
1618                 typeName = arrayPrefix + typeName;
1619             if (type.IsGenericType)
1620             {
1621                 StringBuilder localName = new StringBuilder();
1622                 StringBuilder namespaces = new StringBuilder();
1623                 bool parametersFromBuiltInNamespaces = true;
1624                 int iParam = typeName.IndexOf('[');
1625                 if (iParam >= 0)
1626                     typeName = typeName.Substring(0, iParam);
1627                 IList<int> nestedParamCounts = GetDataContractNameForGenericName(typeName, localName);
1628                 bool isTypeOpenGeneric = type.IsGenericTypeDefinition;
1629                 Type[] genParams = type.GetGenericArguments();
1630                 for (int i = 0; i < genParams.Length; i++)
1631                 {
1632                     Type genParam = genParams[i];
1633                     if (isTypeOpenGeneric)
1634                         localName.Append("{").Append(i).Append("}");
1635                     else
1636                     {
1637                         XmlQualifiedName qname = DataContract.GetStableName(genParam);
1638                         localName.Append(qname.Name);
1639                         namespaces.Append(" ").Append(qname.Namespace);
1640                         if (parametersFromBuiltInNamespaces)
1641                             parametersFromBuiltInNamespaces = IsBuiltInNamespace(qname.Namespace);
1642                     }
1643                 }
1644                 if (isTypeOpenGeneric)
1645                     localName.Append("{#}");
1646                 else if (nestedParamCounts.Count > 1 || !parametersFromBuiltInNamespaces)
1647                 {
1648                     foreach (int count in nestedParamCounts)
1649                         namespaces.Insert(0, count).Insert(0, " ");
1650                     localName.Append(GetNamespacesDigest(namespaces.ToString()));
1651                 }
1652                 typeName = localName.ToString();
1653             }
1654             return DataContract.EncodeLocalName(typeName);
1655         }
1656
1657         static string GetDefaultDataContractNamespace(Type type)
1658         {
1659             string clrNs = type.Namespace;
1660             if (clrNs == null)
1661                 clrNs = String.Empty;
1662             string ns = GetGlobalDataContractNamespace(clrNs, type.Module);
1663             if (ns == null)
1664                 ns = GetGlobalDataContractNamespace(clrNs, type.Assembly);
1665
1666             if (ns == null)
1667                 ns = GetDefaultStableNamespace(type);
1668             else
1669                 CheckExplicitDataContractNamespaceUri(ns, type);
1670             return ns;
1671         }
1672
1673         internal static IList<int> GetDataContractNameForGenericName(string typeName, StringBuilder localName)
1674         {
1675             List<int> nestedParamCounts = new List<int>();
1676             for (int startIndex = 0, endIndex;;)
1677             {
1678                 endIndex = typeName.IndexOf('`', startIndex);
1679                 if (endIndex < 0)
1680                 {
1681                     if (localName != null)
1682                         localName.Append(typeName.Substring(startIndex));
1683                     nestedParamCounts.Add(0);
1684                     break;
1685                 }
1686                 if (localName != null)
1687                     localName.Append(typeName.Substring(startIndex, endIndex - startIndex));
1688                 while ((startIndex = typeName.IndexOf('.', startIndex + 1, endIndex - startIndex - 1)) >= 0)
1689                     nestedParamCounts.Add(0);
1690                 startIndex = typeName.IndexOf('.', endIndex);
1691                 if (startIndex < 0)
1692                 {
1693                     nestedParamCounts.Add(Int32.Parse(typeName.Substring(endIndex + 1), CultureInfo.InvariantCulture));
1694                     break;
1695                 }
1696                 else
1697                     nestedParamCounts.Add(Int32.Parse(typeName.Substring(endIndex + 1, startIndex - endIndex - 1), CultureInfo.InvariantCulture));
1698             }
1699             if (localName != null)
1700                 localName.Append("Of");
1701             return nestedParamCounts;
1702         }
1703
1704         internal static bool IsBuiltInNamespace(string ns)
1705         {
1706             return (ns == Globals.SchemaNamespace || ns == Globals.SerializationNamespace);
1707         }
1708
1709         internal static string GetDefaultStableNamespace(Type type)
1710         {
1711             if (type.IsGenericParameter)
1712                 return "{ns}";
1713             return GetDefaultStableNamespace(type.Namespace);
1714         }
1715
1716         internal static XmlQualifiedName CreateQualifiedName(string localName, string ns)
1717         {
1718             return new XmlQualifiedName(localName, GetNamespace(ns));
1719         }
1720
1721         internal static string GetDefaultStableNamespace(string clrNs)
1722         {
1723             if (clrNs == null) clrNs = String.Empty;
1724             return new Uri(Globals.DataContractXsdBaseNamespaceUri, clrNs).AbsoluteUri;
1725         }
1726
1727         static void CheckExplicitDataContractNamespaceUri(string dataContractNs, Type type)
1728         {
1729             if (dataContractNs.Length > 0)
1730             {
1731                 string trimmedNs = dataContractNs.Trim();
1732                 // Code similar to XmlConvert.ToUri (string.Empty is a valid uri but not "   ")
1733                 if (trimmedNs.Length == 0 || trimmedNs.IndexOf("##", StringComparison.Ordinal) != -1)
1734                     ThrowInvalidDataContractException(SR.GetString(SR.DataContractNamespaceIsNotValid, dataContractNs), type);
1735                 dataContractNs = trimmedNs;
1736             }
1737             Uri uri;
1738             if (Uri.TryCreate(dataContractNs, UriKind.RelativeOrAbsolute, out uri))
1739             {
1740                 if (uri.ToString() == Globals.SerializationNamespace)
1741                     ThrowInvalidDataContractException(SR.GetString(SR.DataContractNamespaceReserved, Globals.SerializationNamespace), type);
1742             }
1743             else
1744                 ThrowInvalidDataContractException(SR.GetString(SR.DataContractNamespaceIsNotValid, dataContractNs), type);
1745         }
1746
1747         internal static string GetClrTypeFullName(Type type)
1748         {
1749             return !type.IsGenericTypeDefinition && type.ContainsGenericParameters ? String.Format(CultureInfo.InvariantCulture, "{0}.{1}", type.Namespace, type.Name) : type.FullName;
1750         }
1751
1752         internal static string GetClrAssemblyName(Type type, out bool hasTypeForwardedFrom)
1753         {
1754             hasTypeForwardedFrom = false;
1755             object[] typeAttributes = type.GetCustomAttributes(typeof(TypeForwardedFromAttribute), false);
1756             if (typeAttributes != null && typeAttributes.Length > 0)
1757             {
1758                 TypeForwardedFromAttribute typeForwardedFromAttribute = (TypeForwardedFromAttribute)typeAttributes[0];
1759                 hasTypeForwardedFrom = true;
1760                 return typeForwardedFromAttribute.AssemblyFullName;
1761             }
1762             else
1763             {
1764                 return type.Assembly.FullName;
1765             }
1766         }
1767
1768         internal static string GetClrTypeFullNameUsingTypeForwardedFromAttribute(Type type)
1769         {
1770             if (type.IsArray)
1771             {
1772                 return GetClrTypeFullNameForArray(type);
1773             }
1774             else
1775             {
1776                 return GetClrTypeFullNameForNonArrayTypes(type);
1777             }
1778         }
1779
1780         static string GetClrTypeFullNameForArray(Type type)
1781         {
1782             return String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}",
1783                 GetClrTypeFullNameUsingTypeForwardedFromAttribute(type.GetElementType()), Globals.OpenBracket, Globals.CloseBracket);
1784         }
1785
1786         static string GetClrTypeFullNameForNonArrayTypes(Type type)
1787         {
1788             if (!type.IsGenericType)
1789             {
1790                 return DataContract.GetClrTypeFullName(type);
1791             }
1792
1793             Type[] genericArguments = type.GetGenericArguments();
1794             StringBuilder builder = new StringBuilder(type.GetGenericTypeDefinition().FullName).Append(Globals.OpenBracket);
1795
1796             foreach (Type genericArgument in genericArguments)
1797             {
1798                 bool hasTypeForwardedFrom;
1799                 builder.Append(Globals.OpenBracket).Append(GetClrTypeFullNameUsingTypeForwardedFromAttribute(genericArgument)).Append(Globals.Comma);
1800                 builder.Append(Globals.Space).Append(GetClrAssemblyName(genericArgument, out hasTypeForwardedFrom));
1801                 builder.Append(Globals.CloseBracket).Append(Globals.Comma);
1802             }
1803
1804             //remove the last comma and close typename for generic with a close bracket
1805             return builder.Remove(builder.Length - 1, 1).Append(Globals.CloseBracket).ToString();
1806         }
1807
1808         internal static void GetClrNameAndNamespace(string fullTypeName, out string localName, out string ns)
1809         {
1810             int nsEnd = fullTypeName.LastIndexOf('.');
1811             if (nsEnd < 0)
1812             {
1813                 ns = String.Empty;
1814                 localName = fullTypeName.Replace('+', '.');
1815             }
1816             else
1817             {
1818                 ns = fullTypeName.Substring(0, nsEnd);
1819                 localName = fullTypeName.Substring(nsEnd + 1).Replace('+', '.');
1820             }
1821             int iParam = localName.IndexOf('[');
1822             if (iParam >= 0)
1823                 localName = localName.Substring(0, iParam);
1824         }
1825
1826         internal static void GetDefaultStableName(string fullTypeName, out string localName, out string ns)
1827         {
1828             CodeTypeReference typeReference = new CodeTypeReference(fullTypeName);
1829             GetDefaultStableName(typeReference, out localName, out ns);
1830         }
1831
1832         static void GetDefaultStableName(CodeTypeReference typeReference, out string localName, out string ns)
1833         {
1834             string fullTypeName = typeReference.BaseType;
1835             DataContract dataContract = GetBuiltInDataContract(fullTypeName);
1836             if (dataContract != null)
1837             {
1838                 localName = dataContract.StableName.Name;
1839                 ns = dataContract.StableName.Namespace;
1840                 return;
1841             }
1842             GetClrNameAndNamespace(fullTypeName, out localName, out ns);
1843             if (typeReference.TypeArguments.Count > 0)
1844             {
1845                 StringBuilder localNameBuilder = new StringBuilder();
1846                 StringBuilder argNamespacesBuilder = new StringBuilder();
1847                 bool parametersFromBuiltInNamespaces = true;
1848                 IList<int> nestedParamCounts = GetDataContractNameForGenericName(localName, localNameBuilder);
1849                 foreach (CodeTypeReference typeArg in typeReference.TypeArguments)
1850                 {
1851                     string typeArgName, typeArgNs;
1852                     GetDefaultStableName(typeArg, out typeArgName, out typeArgNs);
1853                     localNameBuilder.Append(typeArgName);
1854                     argNamespacesBuilder.Append(" ").Append(typeArgNs);
1855                     if (parametersFromBuiltInNamespaces)
1856                         parametersFromBuiltInNamespaces = IsBuiltInNamespace(typeArgNs);
1857                 }
1858                 if (nestedParamCounts.Count > 1 || !parametersFromBuiltInNamespaces)
1859                 {
1860                     foreach (int count in nestedParamCounts)
1861                         argNamespacesBuilder.Insert(0, count).Insert(0, " ");
1862                     localNameBuilder.Append(GetNamespacesDigest(argNamespacesBuilder.ToString()));
1863                 }
1864                 localName = localNameBuilder.ToString();
1865             }
1866             localName = DataContract.EncodeLocalName(localName);
1867             ns = GetDefaultStableNamespace(ns);
1868         }
1869
1870         internal static string GetDataContractNamespaceFromUri(string uriString)
1871         {
1872             return uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal) ? uriString.Substring(Globals.DataContractXsdBaseNamespace.Length) : uriString;
1873         }
1874
1875         static string GetGlobalDataContractNamespace(string clrNs, ICustomAttributeProvider customAttribuetProvider)
1876         {
1877             object[] nsAttributes = customAttribuetProvider.GetCustomAttributes(typeof(ContractNamespaceAttribute), false);
1878             string dataContractNs = null;
1879             for (int i = 0; i < nsAttributes.Length; i++)
1880             {
1881                 ContractNamespaceAttribute nsAttribute = (ContractNamespaceAttribute)nsAttributes[i];
1882                 string clrNsInAttribute = nsAttribute.ClrNamespace;
1883                 if (clrNsInAttribute == null)
1884                     clrNsInAttribute = String.Empty;
1885                 if (clrNsInAttribute == clrNs)
1886                 {
1887                     if (nsAttribute.ContractNamespace == null)
1888                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidGlobalDataContractNamespace, clrNs)));
1889                     if (dataContractNs != null)
1890                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.DataContractNamespaceAlreadySet, dataContractNs, nsAttribute.ContractNamespace, clrNs)));
1891                     dataContractNs = nsAttribute.ContractNamespace;
1892                 }
1893             }
1894             return dataContractNs;
1895         }
1896
1897         private static string GetNamespacesDigest(string namespaces)
1898         {
1899             byte[] namespaceBytes = Encoding.UTF8.GetBytes(namespaces);
1900             byte[] digestBytes = HashHelper.ComputeHash(namespaceBytes);
1901             char[] digestChars = new char[24];
1902             const int digestLen = 6;
1903             int digestCharsLen = Convert.ToBase64CharArray(digestBytes, 0, digestLen, digestChars, 0);
1904             StringBuilder digest = new StringBuilder();
1905             for (int i = 0; i < digestCharsLen; i++)
1906             {
1907                 char ch = digestChars[i];
1908                 switch (ch)
1909                 {
1910                     case '=':
1911                         break;
1912                     case '/':
1913                         digest.Append("_S");
1914                         break;
1915                     case '+':
1916                         digest.Append("_P");
1917                         break;
1918                     default:
1919                         digest.Append(ch);
1920                         break;
1921                 }
1922             }
1923             return digest.ToString();
1924         }
1925
1926         private static string ExpandGenericParameters(string format, Type type)
1927         {
1928             GenericNameProvider genericNameProviderForType = new GenericNameProvider(type);
1929             return ExpandGenericParameters(format, genericNameProviderForType);
1930         }
1931
1932         internal static string ExpandGenericParameters(string format, IGenericNameProvider genericNameProvider)
1933         {
1934             string digest = null;
1935             StringBuilder typeName = new StringBuilder();
1936             IList<int> nestedParameterCounts = genericNameProvider.GetNestedParameterCounts();
1937             for (int i = 0; i < format.Length; i++)
1938             {
1939                 char ch = format[i];
1940                 if (ch == '{')
1941                 {
1942                     i++;
1943                     int start = i;
1944                     for (; i < format.Length; i++)
1945                         if (format[i] == '}')
1946                             break;
1947                     if (i == format.Length)
1948                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GenericNameBraceMismatch, format, genericNameProvider.GetGenericTypeName())));
1949                     if (format[start] == '#' && i == (start + 1))
1950                     {
1951                         if (nestedParameterCounts.Count > 1 || !genericNameProvider.ParametersFromBuiltInNamespaces)
1952                         {
1953                             if (digest == null)
1954                             {
1955                                 StringBuilder namespaces = new StringBuilder(genericNameProvider.GetNamespaces());
1956                                 foreach (int count in nestedParameterCounts)
1957                                     namespaces.Insert(0, count).Insert(0, " ");
1958                                 digest = GetNamespacesDigest(namespaces.ToString());
1959                             }
1960                             typeName.Append(digest);
1961                         }
1962                     }
1963                     else
1964                     {
1965                         int paramIndex;
1966                         if (!Int32.TryParse(format.Substring(start, i - start), out paramIndex) || paramIndex < 0 || paramIndex >= genericNameProvider.GetParameterCount())
1967                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GenericParameterNotValid, format.Substring(start, i - start), genericNameProvider.GetGenericTypeName(), genericNameProvider.GetParameterCount() - 1)));
1968                         typeName.Append(genericNameProvider.GetParameterName(paramIndex));
1969                     }
1970                 }
1971                 else
1972                     typeName.Append(ch);
1973             }
1974             return typeName.ToString();
1975         }
1976
1977         static internal bool IsTypeNullable(Type type)
1978         {
1979             return !type.IsValueType ||
1980                     (type.IsGenericType &&
1981                     type.GetGenericTypeDefinition() == Globals.TypeOfNullable);
1982         }
1983
1984         public static void ThrowTypeNotSerializable(Type type)
1985         {
1986             ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type);
1987         }
1988
1989 #if !NO_CONFIGURATION
1990         [Fx.Tag.SecurityNote(Critical = "configSection value is fetched under an elevation; need to protected access to it.")]
1991         [SecurityCritical]
1992         static DataContractSerializerSection configSection;
1993         static DataContractSerializerSection ConfigSection
1994         {
1995             [Fx.Tag.SecurityNote(Critical = "Calls Security Critical method DataContractSerializerSection.UnsafeGetSection and stores result in"
1996                 + " SecurityCritical field configSection.")]
1997             [SecurityCritical]
1998             get
1999             {
2000                 if (configSection == null)
2001                     configSection = DataContractSerializerSection.UnsafeGetSection();
2002                 return configSection;
2003             }
2004         }
2005 #endif
2006
2007         internal static DataContractDictionary ImportKnownTypeAttributes(Type type)
2008         {
2009             DataContractDictionary knownDataContracts = null;
2010             Dictionary<Type, Type> typesChecked = new Dictionary<Type, Type>();
2011             ImportKnownTypeAttributes(type, typesChecked, ref knownDataContracts);
2012             return knownDataContracts;
2013         }
2014
2015         [SuppressMessage(FxCop.Category.Usage, "CA2301:EmbeddableTypesInContainersRule", MessageId = "typesChecked", Justification = "No need to support type equivalence here.")]
2016         static void ImportKnownTypeAttributes(Type type, Dictionary<Type, Type> typesChecked, ref DataContractDictionary knownDataContracts)
2017         {
2018             if (TD.ImportKnownTypesStartIsEnabled())
2019             {
2020                 TD.ImportKnownTypesStart();
2021             }
2022
2023             while (type != null && DataContract.IsTypeSerializable(type))
2024             {
2025                 if (typesChecked.ContainsKey(type))
2026                     return;
2027
2028                 typesChecked.Add(type, type);
2029                 object[] knownTypeAttributes = type.GetCustomAttributes(Globals.TypeOfKnownTypeAttribute, false);
2030                 if (knownTypeAttributes != null)
2031                 {
2032                     KnownTypeAttribute kt;
2033                     bool useMethod = false, useType = false;
2034                     for (int i = 0; i < knownTypeAttributes.Length; ++i)
2035                     {
2036                         kt = (KnownTypeAttribute)knownTypeAttributes[i];
2037                         if (kt.Type != null)
2038                         {
2039                             if (useMethod)
2040                             {
2041                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeOneScheme, DataContract.GetClrTypeFullName(type)), type);
2042                             }
2043
2044                             CheckAndAdd(kt.Type, typesChecked, ref knownDataContracts);
2045                             useType = true;
2046                         }
2047                         else
2048                         {
2049                             if (useMethod || useType)
2050                             {
2051                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeOneScheme, DataContract.GetClrTypeFullName(type)), type);
2052                             }
2053
2054                             string methodName = kt.MethodName;
2055                             if (methodName == null)
2056                             {
2057                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeNoData, DataContract.GetClrTypeFullName(type)), type);
2058                             }
2059
2060                             if (methodName.Length == 0)
2061                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeEmptyString, DataContract.GetClrTypeFullName(type)), type);
2062
2063                             MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
2064                             if (method == null)
2065                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeUnknownMethod, methodName, DataContract.GetClrTypeFullName(type)), type);
2066
2067                             if (!Globals.TypeOfTypeEnumerable.IsAssignableFrom(method.ReturnType))
2068                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeReturnType, DataContract.GetClrTypeFullName(type), methodName), type);
2069
2070                             object types = method.Invoke(null, Globals.EmptyObjectArray);
2071                             if (types == null)
2072                             {
2073                                 DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeMethodNull, DataContract.GetClrTypeFullName(type)), type);
2074                             }
2075
2076                             foreach (Type ty in (IEnumerable<Type>)types)
2077                             {
2078                                 if (ty == null)
2079                                     DataContract.ThrowInvalidDataContractException(SR.GetString(SR.KnownTypeAttributeValidMethodTypes, DataContract.GetClrTypeFullName(type)), type);
2080
2081                                 CheckAndAdd(ty, typesChecked, ref knownDataContracts);
2082                             }
2083
2084                             useMethod = true;
2085                         }
2086                     }
2087                 }
2088
2089                 LoadKnownTypesFromConfig(type, typesChecked, ref knownDataContracts);
2090
2091                 type = type.BaseType;
2092             }
2093
2094             if (TD.ImportKnownTypesStopIsEnabled())
2095             {
2096                 TD.ImportKnownTypesStop();
2097             }
2098         }
2099
2100         [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical property ConfigSection.",
2101             Safe = "Completely processes ConfigSection and only makes available the processed result."
2102             + " The ConfigSection instance is not leaked.")]
2103         [SecuritySafeCritical]
2104         static void LoadKnownTypesFromConfig(Type type, Dictionary<Type, Type> typesChecked, ref DataContractDictionary knownDataContracts)
2105         {
2106 #if !NO_CONFIGURATION
2107             // Pull known types from config
2108             if (ConfigSection != null)
2109             {
2110                 DeclaredTypeElementCollection elements = ConfigSection.DeclaredTypes;
2111
2112                 Type rootType = type;
2113                 Type[] genArgs = null;
2114
2115                 CheckRootTypeInConfigIsGeneric(type, ref rootType, ref genArgs);
2116
2117                 DeclaredTypeElement elem = elements[rootType.AssemblyQualifiedName];
2118                 if (elem != null)
2119                 {
2120                     if (IsElemTypeNullOrNotEqualToRootType(elem.Type, rootType))
2121                     {
2122                         elem = null;
2123                     }
2124                 }
2125
2126                 if (elem == null)
2127                 {
2128                     for (int i = 0; i < elements.Count; ++i)
2129                     {
2130                         if (IsCollectionElementTypeEqualToRootType(elements[i].Type, rootType))
2131                         {
2132                             elem = elements[i];
2133                             break;
2134                         }
2135                     }
2136                 }
2137
2138                 if (elem != null)
2139                 {
2140                     for (int i = 0; i < elem.KnownTypes.Count; ++i)
2141                     {
2142                         Type knownType = elem.KnownTypes[i].GetType(elem.Type, genArgs);
2143                         if (knownType != null)
2144                         {
2145                             CheckAndAdd(knownType, typesChecked, ref knownDataContracts);
2146                         }
2147                     }
2148                 }
2149             }
2150 #endif
2151         }
2152
2153         private static void CheckRootTypeInConfigIsGeneric(Type type, ref Type rootType, ref Type[] genArgs)
2154         {
2155             if (rootType.IsGenericType)
2156             {
2157                 if (!rootType.ContainsGenericParameters)
2158                 {
2159                     genArgs = rootType.GetGenericArguments();
2160                     rootType = rootType.GetGenericTypeDefinition();
2161                 }
2162                 else
2163                 {
2164                     DataContract.ThrowInvalidDataContractException(SR.GetString(SR.TypeMustBeConcrete, type), type);
2165                 }
2166             }
2167         }
2168
2169         private static bool IsElemTypeNullOrNotEqualToRootType(string elemTypeName, Type rootType)
2170         {
2171             Type t = Type.GetType(elemTypeName, false);
2172             if (t == null || !rootType.Equals(t))
2173             {
2174                 return true;
2175             }
2176             return false;
2177         }
2178
2179         private static bool IsCollectionElementTypeEqualToRootType(string collectionElementTypeName, Type rootType)
2180         {
2181             if (collectionElementTypeName.StartsWith(DataContract.GetClrTypeFullName(rootType), StringComparison.Ordinal))
2182             {
2183                 Type t = Type.GetType(collectionElementTypeName, false);
2184                 if (t != null)
2185                 {
2186                     if (t.IsGenericType && !IsOpenGenericType(t))
2187                     {
2188                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.KnownTypeConfigClosedGenericDeclared, collectionElementTypeName)));
2189                     }
2190                     else if (rootType.Equals(t))
2191                     {
2192                         return true;
2193                     }
2194                 }
2195             }
2196             return false;
2197         }
2198
2199         [Fx.Tag.SecurityNote(Critical = "Fetches the critical dataContractAdapterType.",
2200             Safe = "The critical dataContractAdapterType is only used for local comparison and is not leaked beyond this method.")]
2201         [SecurityCritical, SecurityTreatAsSafe]
2202         internal static void CheckAndAdd(Type type, Dictionary<Type, Type> typesChecked, ref DataContractDictionary nameToDataContractTable)
2203         {
2204             type = DataContract.UnwrapNullableType(type);
2205             DataContract dataContract = DataContract.GetDataContract(type);
2206             DataContract alreadyExistingContract;
2207             if (nameToDataContractTable == null)
2208             {
2209                 nameToDataContractTable = new DataContractDictionary();
2210             }
2211             else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out alreadyExistingContract))
2212             {
2213                 if (alreadyExistingContract.UnderlyingType != DataContractCriticalHelper.GetDataContractAdapterType(type))
2214                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DupContractInKnownTypes, type, alreadyExistingContract.UnderlyingType, dataContract.StableName.Namespace, dataContract.StableName.Name)));
2215                 return;
2216             }
2217             nameToDataContractTable.Add(dataContract.StableName, dataContract);
2218             ImportKnownTypeAttributes(type, typesChecked, ref nameToDataContractTable);
2219         }
2220
2221         static bool IsOpenGenericType(Type t)
2222         {
2223             Type[] args = t.GetGenericArguments();
2224             for (int i = 0; i < args.Length; ++i)
2225                 if (!args[i].IsGenericParameter)
2226                     return false;
2227
2228             return true;
2229         }
2230
2231         public sealed override bool Equals(object other)
2232         {
2233             if ((object)this == other)
2234                 return true;
2235             return Equals(other, new Dictionary<DataContractPairKey, object>());
2236         }
2237
2238         internal virtual bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
2239         {
2240             DataContract dataContract = other as DataContract;
2241             if (dataContract != null)
2242             {
2243                 return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace && IsReference == dataContract.IsReference);
2244             }
2245             return false;
2246         }
2247
2248         internal bool IsEqualOrChecked(object other, Dictionary<DataContractPairKey, object> checkedContracts)
2249         {
2250             if ((object)this == other)
2251                 return true;
2252
2253             if (checkedContracts != null)
2254             {
2255                 DataContractPairKey contractPairKey = new DataContractPairKey(this, other);
2256                 if (checkedContracts.ContainsKey(contractPairKey))
2257                     return true;
2258                 checkedContracts.Add(contractPairKey, null);
2259             }
2260             return false;
2261         }
2262
2263         public override int GetHashCode()
2264         {
2265             return base.GetHashCode();
2266         }
2267
2268         internal void ThrowInvalidDataContractException(string message)
2269         {
2270             ThrowInvalidDataContractException(message, UnderlyingType);
2271         }
2272 #if NO_DYNAMIC_CODEGEN
2273         static internal bool IsTypeVisible(Type t)
2274         {
2275             return true;
2276         }
2277 #else
2278         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks type visibility to calculate if access to it requires MemberAccessPermission."
2279             + " Since this information is used to determine whether to give the generated code access"
2280             + " permissions to private members, any changes to the logic should be reviewed.")]
2281         static internal bool IsTypeVisible(Type t)
2282         {
2283             // Generic parameters are always considered visible.
2284             if (t.IsGenericParameter)
2285             {
2286                 return true;
2287             }
2288
2289             // The normal Type.IsVisible check requires all nested types to be IsNestedPublic.
2290             // This does not comply with our convention where they can also have InternalsVisibleTo
2291             // with our assembly.   The following method performs a recursive walk back the declaring
2292             // type hierarchy to perform this enhanced IsVisible check.
2293             if (!IsTypeAndDeclaringTypeVisible(t))
2294             {
2295                 return false;
2296             }
2297
2298             // All generic argument types must also be visible.
2299             // Nested types perform this test recursively for all their declaring types.
2300             foreach (Type genericType in t.GetGenericArguments())
2301             {
2302                 if (!IsTypeVisible(genericType))
2303                 {
2304                     return false;
2305                 }
2306             }
2307
2308             return true;
2309         }
2310
2311         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks type visibility to calculate if access to it requires MemberAccessPermission."
2312             + " Since this information is used to determine whether to give the generated code access"
2313             + " permissions to private members, any changes to the logic should be reviewed.")]
2314         static internal bool IsTypeAndDeclaringTypeVisible(Type t)
2315         {
2316             // Arrays, etc. must consider the underlying element type because the
2317             // non-element type does not reflect the same type nesting.  For example,
2318             // MyClass[] would not show as a nested type, even when MyClass is nested.
2319             if (t.HasElementType)
2320             {
2321                 return IsTypeVisible(t.GetElementType());
2322             }
2323
2324             // Nested types are not visible unless their declaring type is visible.
2325             // Additionally, they must be either IsNestedPublic or in an assembly with InternalsVisibleTo this current assembly.
2326             // Non-nested types must be public or have this same InternalsVisibleTo relation.
2327             return t.IsNested
2328                     ? (t.IsNestedPublic || IsTypeVisibleInSerializationModule(t)) && IsTypeVisible(t.DeclaringType)
2329                     : t.IsPublic || IsTypeVisibleInSerializationModule(t);
2330         }
2331
2332         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks constructor visibility to calculate if access to it requires MemberAccessPermission."
2333             + " note: does local check for visibility, assuming that the declaring Type visibility has been checked."
2334             + " Since this information is used to determine whether to give the generated code access"
2335             + " permissions to private members, any changes to the logic should be reviewed.")]
2336         static internal bool ConstructorRequiresMemberAccess(ConstructorInfo ctor)
2337         {
2338             return ctor != null && !ctor.IsPublic && !IsMemberVisibleInSerializationModule(ctor);
2339         }
2340
2341         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks method visibility to calculate if access to it requires MemberAccessPermission."
2342             + " note: does local check for visibility, assuming that the declaring Type visibility has been checked."
2343             + " Since this information is used to determine whether to give the generated code access"
2344             + " permissions to private members, any changes to the logic should be reviewed.")]
2345         static internal bool MethodRequiresMemberAccess(MethodInfo method)
2346         {
2347             return method != null && !method.IsPublic && !IsMemberVisibleInSerializationModule(method);
2348         }
2349
2350         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks field visibility to calculate if access to it requires MemberAccessPermission."
2351             + " note: does local check for visibility, assuming that the declaring Type visibility has been checked."
2352             + " Since this information is used to determine whether to give the generated code access"
2353             + " permissions to private members, any changes to the logic should be reviewed.")]
2354         static internal bool FieldRequiresMemberAccess(FieldInfo field)
2355         {
2356             return field != null && !field.IsPublic && !IsMemberVisibleInSerializationModule(field);
2357         }
2358
2359         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks type visibility to calculate if access to it requires MemberAccessPermission."
2360             + " note: does local check for visibility, assuming that the declaring Type visibility has been checked."
2361             + " Since this information is used to determine whether to give the generated code access"
2362             + " permissions to private members, any changes to the logic should be reviewed.")]
2363         static bool IsTypeVisibleInSerializationModule(Type type)
2364         {
2365             return (type.Module.Equals(typeof(CodeGenerator).Module) || IsAssemblyFriendOfSerialization(type.Assembly)) && !type.IsNestedPrivate;
2366         }
2367
2368         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks member visibility to calculate if access to it requires MemberAccessPermission."
2369             + " note: does local check for visibility, assuming that the declaring Type visibility has been checked."
2370             + " Since this information is used to determine whether to give the generated code access"
2371             + " permissions to private members, any changes to the logic should be reviewed.")]
2372         static bool IsMemberVisibleInSerializationModule(MemberInfo member)
2373         {
2374             if (!IsTypeVisibleInSerializationModule(member.DeclaringType))
2375                 return false;
2376
2377             if (member is MethodInfo)
2378             {
2379                 MethodInfo method = (MethodInfo)member;
2380                 return (method.IsAssembly || method.IsFamilyOrAssembly);
2381             }
2382             else if (member is FieldInfo)
2383             {
2384                 FieldInfo field = (FieldInfo)member;
2385                 return (field.IsAssembly || field.IsFamilyOrAssembly) && IsTypeVisible(field.FieldType);
2386             }
2387             else if (member is ConstructorInfo)
2388             {
2389                 ConstructorInfo constructor = (ConstructorInfo)member;
2390                 return (constructor.IsAssembly || constructor.IsFamilyOrAssembly);
2391             }
2392
2393             return false;
2394         }
2395
2396         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - checks member visibility to calculate if access to it requires MemberAccessPermission."
2397             + " Since this information is used to determine whether to give the generated code access"
2398             + " permissions to private members, any changes to the logic should be reviewed.")]
2399         internal static bool IsAssemblyFriendOfSerialization(Assembly assembly)
2400         {
2401             InternalsVisibleToAttribute[] internalsVisibleAttributes = (InternalsVisibleToAttribute[])assembly.GetCustomAttributes(typeof(InternalsVisibleToAttribute), false);
2402             foreach (InternalsVisibleToAttribute internalsVisibleAttribute in internalsVisibleAttributes)
2403             {
2404                 string internalsVisibleAttributeAssemblyName = internalsVisibleAttribute.AssemblyName;
2405
2406                 if (Regex.IsMatch(internalsVisibleAttributeAssemblyName, Globals.SimpleSRSInternalsVisiblePattern) ||
2407                     Regex.IsMatch(internalsVisibleAttributeAssemblyName, Globals.FullSRSInternalsVisiblePattern))
2408                 {
2409                     return true;
2410                 }
2411             }
2412             return false;
2413         }
2414 #endif
2415     }
2416
2417     interface IGenericNameProvider
2418     {
2419         int GetParameterCount();
2420         IList<int> GetNestedParameterCounts();
2421         string GetParameterName(int paramIndex);
2422         string GetNamespaces();
2423         string GetGenericTypeName();
2424         bool ParametersFromBuiltInNamespaces { get; }
2425     }
2426
2427     class GenericNameProvider : IGenericNameProvider
2428     {
2429         string genericTypeName;
2430         object[] genericParams; //Type or DataContract
2431         IList<int> nestedParamCounts;
2432         internal GenericNameProvider(Type type)
2433             : this(DataContract.GetClrTypeFullName(type.GetGenericTypeDefinition()), type.GetGenericArguments())
2434         {
2435         }
2436
2437         internal GenericNameProvider(string genericTypeName, object[] genericParams)
2438         {
2439             this.genericTypeName = genericTypeName;
2440             this.genericParams = new object[genericParams.Length];
2441             genericParams.CopyTo(this.genericParams, 0);
2442
2443             string name, ns;
2444             DataContract.GetClrNameAndNamespace(genericTypeName, out name, out ns);
2445             this.nestedParamCounts = DataContract.GetDataContractNameForGenericName(name, null);
2446         }
2447
2448         public int GetParameterCount()
2449         {
2450             return genericParams.Length;
2451         }
2452
2453         public IList<int> GetNestedParameterCounts()
2454         {
2455             return nestedParamCounts;
2456         }
2457
2458         public string GetParameterName(int paramIndex)
2459         {
2460             return GetStableName(paramIndex).Name;
2461         }
2462
2463         public string GetNamespaces()
2464         {
2465             StringBuilder namespaces = new StringBuilder();
2466             for (int j = 0; j < GetParameterCount(); j++)
2467                 namespaces.Append(" ").Append(GetStableName(j).Namespace);
2468             return namespaces.ToString();
2469         }
2470
2471         public string GetGenericTypeName()
2472         {
2473             return genericTypeName;
2474         }
2475
2476         public bool ParametersFromBuiltInNamespaces
2477         {
2478             get
2479             {
2480                 bool parametersFromBuiltInNamespaces = true;
2481                 for (int j = 0; j < GetParameterCount(); j++)
2482                 {
2483                     if (parametersFromBuiltInNamespaces)
2484                         parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(GetStableName(j).Namespace);
2485                     else
2486                         break;
2487                 }
2488                 return parametersFromBuiltInNamespaces;
2489             }
2490         }
2491
2492         XmlQualifiedName GetStableName(int i)
2493         {
2494             object o = genericParams[i];
2495             XmlQualifiedName qname = o as XmlQualifiedName;
2496             if (qname == null)
2497             {
2498                 Type paramType = o as Type;
2499                 if (paramType != null)
2500                     genericParams[i] = qname = DataContract.GetStableName(paramType);
2501                 else
2502                     genericParams[i] = qname = ((DataContract)o).StableName;
2503             }
2504             return qname;
2505         }
2506     }
2507
2508     class GenericInfo : IGenericNameProvider
2509     {
2510         string genericTypeName;
2511         XmlQualifiedName stableName;
2512         List<GenericInfo> paramGenericInfos;
2513         List<int> nestedParamCounts;
2514
2515         internal GenericInfo(XmlQualifiedName stableName, string genericTypeName)
2516         {
2517             this.stableName = stableName;
2518             this.genericTypeName = genericTypeName;
2519             this.nestedParamCounts = new List<int>();
2520             this.nestedParamCounts.Add(0);
2521         }
2522
2523         internal void Add(GenericInfo actualParamInfo)
2524         {
2525             if (paramGenericInfos == null)
2526                 paramGenericInfos = new List<GenericInfo>();
2527             paramGenericInfos.Add(actualParamInfo);
2528         }
2529
2530         internal void AddToLevel(int level, int count)
2531         {
2532             if (level >= nestedParamCounts.Count)
2533             {
2534                 do
2535                 {
2536                     nestedParamCounts.Add((level == nestedParamCounts.Count) ? count : 0);
2537                 } while (level >= nestedParamCounts.Count);
2538             }
2539             else
2540                 nestedParamCounts[level] = nestedParamCounts[level] + count;
2541         }
2542
2543         internal XmlQualifiedName GetExpandedStableName()
2544         {
2545             if (paramGenericInfos == null)
2546                 return stableName;
2547             return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), this)), stableName.Namespace);
2548         }
2549
2550         internal string GetStableNamespace()
2551         {
2552             return stableName.Namespace;
2553         }
2554
2555         internal XmlQualifiedName StableName
2556         {
2557             get { return stableName; }
2558         }
2559
2560         internal IList<GenericInfo> Parameters
2561         {
2562             get { return paramGenericInfos; }
2563         }
2564
2565         public int GetParameterCount()
2566         {
2567             return paramGenericInfos.Count;
2568         }
2569
2570         public IList<int> GetNestedParameterCounts()
2571         {
2572             return nestedParamCounts;
2573         }
2574
2575         public string GetParameterName(int paramIndex)
2576         {
2577             return paramGenericInfos[paramIndex].GetExpandedStableName().Name;
2578         }
2579
2580         public string GetNamespaces()
2581         {
2582             StringBuilder namespaces = new StringBuilder();
2583             for (int j = 0; j < paramGenericInfos.Count; j++)
2584                 namespaces.Append(" ").Append(paramGenericInfos[j].GetStableNamespace());
2585             return namespaces.ToString();
2586         }
2587
2588         public string GetGenericTypeName()
2589         {
2590             return genericTypeName;
2591         }
2592
2593         public bool ParametersFromBuiltInNamespaces
2594         {
2595             get
2596             {
2597                 bool parametersFromBuiltInNamespaces = true;
2598                 for (int j = 0; j < paramGenericInfos.Count; j++)
2599                 {
2600                     if (parametersFromBuiltInNamespaces)
2601                         parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(paramGenericInfos[j].GetStableNamespace());
2602                     else
2603                         break;
2604                 }
2605                 return parametersFromBuiltInNamespaces;
2606             }
2607         }
2608
2609     }
2610
2611     internal class DataContractPairKey
2612     {
2613         object object1;
2614         object object2;
2615
2616         public DataContractPairKey(object object1, object object2)
2617         {
2618             this.object1 = object1;
2619             this.object2 = object2;
2620         }
2621
2622         public override bool Equals(object other)
2623         {
2624             DataContractPairKey otherKey = other as DataContractPairKey;
2625             if (otherKey == null)
2626                 return false;
2627             return ((otherKey.object1 == object1 && otherKey.object2 == object2) || (otherKey.object1 == object2 && otherKey.object2 == object1));
2628         }
2629
2630         public override int GetHashCode()
2631         {
2632             return object1.GetHashCode() ^ object2.GetHashCode();
2633         }
2634     }
2635
2636     class TypeHandleRefEqualityComparer : IEqualityComparer<TypeHandleRef>
2637     {
2638         public bool Equals(TypeHandleRef x, TypeHandleRef y)
2639         {
2640             return x.Value.Equals(y.Value);
2641         }
2642
2643         public int GetHashCode(TypeHandleRef obj)
2644         {
2645             return obj.Value.GetHashCode();
2646         }
2647     }
2648
2649     class TypeHandleRef
2650     {
2651         RuntimeTypeHandle value;
2652
2653         public TypeHandleRef()
2654         {
2655         }
2656
2657         public TypeHandleRef(RuntimeTypeHandle value)
2658         {
2659             this.value = value;
2660         }
2661
2662         public RuntimeTypeHandle Value
2663         {
2664             get
2665             {
2666                 return this.value;
2667             }
2668             set
2669             {
2670                 this.value = value;
2671             }
2672         }
2673     }
2674
2675     class IntRef
2676     {
2677         int value;
2678
2679         public IntRef(int value)
2680         {
2681             this.value = value;
2682         }
2683
2684         public int Value
2685         {
2686             get
2687             {
2688                 return this.value;
2689             }
2690         }
2691     }
2692 }