Add mobile build support in System.Runtime.Serialization.
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Runtime / Serialization / NetDataContractSerializer.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Runtime.Serialization
6 {
7     using System;
8     using System.IO;
9     using System.Xml;
10     using System.Security;
11     using System.Collections;
12     using System.Security.Permissions;
13     using System.Runtime.CompilerServices;
14     using System.Runtime.Serialization.Formatters;
15     using System.Collections.Generic;
16 #if !NO_CONFIGURATION
17     using System.Runtime.Serialization.Configuration;
18 #endif
19     using System.Reflection;
20
21     public sealed class NetDataContractSerializer : XmlObjectSerializer, IFormatter
22     {
23         XmlDictionaryString rootName;
24         XmlDictionaryString rootNamespace;
25         StreamingContext context;
26         SerializationBinder binder;
27         ISurrogateSelector surrogateSelector;
28         int maxItemsInObjectGraph;
29         bool ignoreExtensionDataObject;
30         FormatterAssemblyStyle assemblyFormat;
31         DataContract cachedDataContract;
32         static Hashtable typeNameCache = new Hashtable();
33
34         public NetDataContractSerializer()
35             : this(new StreamingContext(StreamingContextStates.All))
36         {
37         }
38
39         public NetDataContractSerializer(StreamingContext context)
40             : this(context, Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
41         {
42         }
43
44         public NetDataContractSerializer(StreamingContext context,
45             int maxItemsInObjectGraph,
46             bool ignoreExtensionDataObject,
47             FormatterAssemblyStyle assemblyFormat,
48             ISurrogateSelector surrogateSelector)
49         {
50             Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
51         }
52
53         public NetDataContractSerializer(string rootName, string rootNamespace)
54             : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
55         {
56         }
57
58         public NetDataContractSerializer(string rootName, string rootNamespace,
59             StreamingContext context,
60             int maxItemsInObjectGraph,
61             bool ignoreExtensionDataObject,
62             FormatterAssemblyStyle assemblyFormat,
63             ISurrogateSelector surrogateSelector)
64         {
65             XmlDictionary dictionary = new XmlDictionary(2);
66             Initialize(dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
67         }
68
69         public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace)
70             : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
71         {
72         }
73
74         public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
75             StreamingContext context,
76             int maxItemsInObjectGraph,
77             bool ignoreExtensionDataObject,
78             FormatterAssemblyStyle assemblyFormat,
79             ISurrogateSelector surrogateSelector)
80         {
81             Initialize(rootName, rootNamespace, context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
82         }
83
84         void Initialize(StreamingContext context,
85             int maxItemsInObjectGraph,
86             bool ignoreExtensionDataObject,
87             FormatterAssemblyStyle assemblyFormat,
88             ISurrogateSelector surrogateSelector)
89         {
90             this.context = context;
91             if (maxItemsInObjectGraph < 0)
92                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxItemsInObjectGraph", SR.GetString(SR.ValueMustBeNonNegative)));
93             this.maxItemsInObjectGraph = maxItemsInObjectGraph;
94             this.ignoreExtensionDataObject = ignoreExtensionDataObject;
95             this.surrogateSelector = surrogateSelector;
96             this.AssemblyFormat = assemblyFormat;
97         }
98
99         void Initialize(XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
100             StreamingContext context,
101             int maxItemsInObjectGraph,
102             bool ignoreExtensionDataObject,
103             FormatterAssemblyStyle assemblyFormat,
104             ISurrogateSelector surrogateSelector)
105         {
106             Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
107             this.rootName = rootName;
108             this.rootNamespace = rootNamespace;
109         }
110
111         static bool? unsafeTypeForwardingEnabled;
112         internal static bool UnsafeTypeForwardingEnabled
113         {
114             [Fx.Tag.SecurityNote(Critical = "Calls Security Critical method NetDataContractSerializerSection.TryUnsafeGetSection.", Safe = "The ConfigSection instance is not leaked.")]
115             [SecuritySafeCritical]
116             get
117             {
118                 if (unsafeTypeForwardingEnabled == null)
119                 {
120 #if NO_CONFIGURATION
121                     unsafeTypeForwardingEnabled = false;
122 #else
123                     NetDataContractSerializerSection section;
124                     if (NetDataContractSerializerSection.TryUnsafeGetSection(out section))
125                     {
126                         unsafeTypeForwardingEnabled = section.EnableUnsafeTypeForwarding;
127                     }
128                     else
129                     {
130                         unsafeTypeForwardingEnabled = false;
131                     }
132 #endif
133                 }
134                 Fx.Assert(unsafeTypeForwardingEnabled != null, "unsafeTypeForwardingEnabled should not be null.");
135                 return unsafeTypeForwardingEnabled.Value;
136             }
137         }
138
139         public StreamingContext Context
140         {
141             get { return context; }
142             set { context = value; }
143         }
144
145         public SerializationBinder Binder
146         {
147             get { return binder; }
148             set { binder = value; }
149         }
150
151         public ISurrogateSelector SurrogateSelector
152         {
153             get { return surrogateSelector; }
154             set { surrogateSelector = value; }
155         }
156
157         public FormatterAssemblyStyle AssemblyFormat
158         {
159             get { return assemblyFormat; }
160             set
161             {
162                 if (value != FormatterAssemblyStyle.Full && value != FormatterAssemblyStyle.Simple)
163                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidAssemblyFormat, value)));
164                 assemblyFormat = value;
165             }
166         }
167
168         public int MaxItemsInObjectGraph
169         {
170             get { return maxItemsInObjectGraph; }
171         }
172
173         public bool IgnoreExtensionDataObject
174         {
175             get { return ignoreExtensionDataObject; }
176         }
177
178         public void Serialize(Stream stream, object graph)
179         {
180             base.WriteObject(stream, graph);
181         }
182
183         public object Deserialize(Stream stream)
184         {
185             return base.ReadObject(stream);
186         }
187
188         internal override void InternalWriteObject(XmlWriterDelegator writer, object graph)
189         {
190             Hashtable surrogateDataContracts = null;
191             DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
192
193             InternalWriteStartObject(writer, graph, contract);
194             InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts);
195             InternalWriteEndObject(writer);
196         }
197
198         public override void WriteObject(XmlWriter writer, object graph)
199         {
200             WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
201         }
202
203         public override void WriteStartObject(XmlWriter writer, object graph)
204         {
205             WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
206         }
207
208         public override void WriteObjectContent(XmlWriter writer, object graph)
209         {
210             WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
211         }
212
213         public override void WriteEndObject(XmlWriter writer)
214         {
215             WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
216         }
217
218         public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
219         {
220             WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
221         }
222
223         internal override void InternalWriteStartObject(XmlWriterDelegator writer, object graph)
224         {
225             Hashtable surrogateDataContracts = null;
226             DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
227             InternalWriteStartObject(writer, graph, contract);
228         }
229
230         void InternalWriteStartObject(XmlWriterDelegator writer, object graph, DataContract contract)
231         {
232             WriteRootElement(writer, contract, rootName, rootNamespace, CheckIfNeedsContractNsAtRoot(rootName, rootNamespace, contract));
233         }
234
235         public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
236         {
237             WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
238         }
239
240         internal override void InternalWriteObjectContent(XmlWriterDelegator writer, object graph)
241         {
242             Hashtable surrogateDataContracts = null;
243             DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
244             InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts);
245         }
246
247         void InternalWriteObjectContent(XmlWriterDelegator writer, object graph, DataContract contract, Hashtable surrogateDataContracts)
248         {
249             if (MaxItemsInObjectGraph == 0)
250                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
251
252             if (IsRootXmlAny(rootName, contract))
253             {
254                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsAnyNotSupportedByNetDataContractSerializer, contract.UnderlyingType)));
255             }
256             else if (graph == null)
257             {
258                 WriteNull(writer);
259             }
260             else
261             {
262                 Type graphType = graph.GetType();
263                 if (contract.UnderlyingType != graphType)
264                     contract = GetDataContract(graph, ref surrogateDataContracts);
265
266                 XmlObjectSerializerWriteContext context = null;
267                 if (contract.CanContainReferences)
268                 {
269                     context = XmlObjectSerializerWriteContext.CreateContext(this, surrogateDataContracts);
270                     context.HandleGraphAtTopLevel(writer, graph, contract);
271                 }
272
273                 WriteClrTypeInfo(writer, contract, binder);
274                 contract.WriteXmlValue(writer, graph, context);
275             }
276         }
277
278         // Update the overloads whenever you are changing this method
279         internal static void WriteClrTypeInfo(XmlWriterDelegator writer, DataContract dataContract, SerializationBinder binder)
280         {
281             if (!dataContract.IsISerializable && !(dataContract is SurrogateDataContract))
282             {
283                 TypeInformation typeInformation = null;
284                 Type clrType = dataContract.OriginalUnderlyingType;
285                 string clrTypeName = null;
286                 string clrAssemblyName = null;
287
288                 if (binder != null)
289                 {
290                     binder.BindToName(clrType, out clrAssemblyName, out clrTypeName);
291                 }
292
293                 if (clrTypeName == null)
294                 {
295                     typeInformation = NetDataContractSerializer.GetTypeInformation(clrType);
296                     clrTypeName = typeInformation.FullTypeName;
297                 }
298
299                 if (clrAssemblyName == null)
300                 {
301                     clrAssemblyName = (typeInformation == null) ?
302                         NetDataContractSerializer.GetTypeInformation(clrType).AssemblyString :
303                         typeInformation.AssemblyString;
304
305                     // Throw in the [TypeForwardedFrom] case to prevent a partially trusted assembly from forwarding itself to an assembly with higher privileges
306                     if (!UnsafeTypeForwardingEnabled && !clrType.Assembly.IsFullyTrusted && !IsAssemblyNameForwardingSafe(clrType.Assembly.FullName, clrAssemblyName))
307                     {
308                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.TypeCannotBeForwardedFrom, DataContract.GetClrTypeFullName(clrType), clrType.Assembly.FullName, clrAssemblyName)));
309                     }
310                 }
311
312                 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
313             }
314         }
315
316         // Update the overloads whenever you are changing this method
317         internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, string defaultClrTypeName, string defaultClrAssemblyName)
318         {
319             string clrTypeName = null;
320             string clrAssemblyName = null;
321
322             if (binder != null)
323             {
324                 binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName);
325             }
326
327             if (clrTypeName == null)
328             {
329                 clrTypeName = defaultClrTypeName;
330             }
331
332             if (clrAssemblyName == null)
333             {
334                 clrAssemblyName = defaultClrAssemblyName;
335             }
336
337             WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
338         }
339
340         // Update the overloads whenever you are changing this method
341         internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, SerializationInfo serInfo)
342         {
343             TypeInformation typeInformation = null;
344             string clrTypeName = null;
345             string clrAssemblyName = null;
346
347             if (binder != null)
348             {
349                 binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName);
350             }
351
352             if (clrTypeName == null)
353             {
354                 if (serInfo.IsFullTypeNameSetExplicit)
355                 {
356                     clrTypeName = serInfo.FullTypeName;
357                 }
358                 else
359                 {
360                     typeInformation = NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType);
361                     clrTypeName = typeInformation.FullTypeName;
362                 }
363             }
364
365             if (clrAssemblyName == null)
366             {
367                 if (serInfo.IsAssemblyNameSetExplicit)
368                 {
369                     clrAssemblyName = serInfo.AssemblyName;
370                 }
371                 else
372                 {
373                     clrAssemblyName = (typeInformation == null) ?
374                     NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType).AssemblyString :
375                     typeInformation.AssemblyString;
376                 }
377             }
378
379             WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
380         }
381
382         static void WriteClrTypeInfo(XmlWriterDelegator writer, string clrTypeName, string clrAssemblyName)
383         {
384             if (clrTypeName != null)
385                 writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrTypeName));
386             if (clrAssemblyName != null)
387                 writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrAssemblyLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrAssemblyName));
388         }
389
390         public override void WriteEndObject(XmlDictionaryWriter writer)
391         {
392             WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
393         }
394
395         internal override void InternalWriteEndObject(XmlWriterDelegator writer)
396         {
397             writer.WriteEndElement();
398         }
399
400         public override object ReadObject(XmlReader reader)
401         {
402             return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/);
403         }
404
405         public override object ReadObject(XmlReader reader, bool verifyObjectName)
406         {
407             return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
408         }
409
410         public override bool IsStartObject(XmlReader reader)
411         {
412             return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
413         }
414
415         public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
416         {
417             return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
418         }
419
420         public override bool IsStartObject(XmlDictionaryReader reader)
421         {
422             return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
423         }
424
425         internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName)
426         {
427             if (MaxItemsInObjectGraph == 0)
428                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
429
430             // verifyObjectName has no effect in SharedType mode
431             if (!IsStartElement(xmlReader))
432             {
433                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.GetString(SR.ExpectingElementAtDeserialize, XmlNodeType.Element), xmlReader));
434             }
435
436             XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext.CreateContext(this);
437             return context.InternalDeserialize(xmlReader, null, null, null);
438         }
439
440         internal override bool InternalIsStartObject(XmlReaderDelegator reader)
441         {
442             return IsStartElement(reader);
443         }
444
445         internal DataContract GetDataContract(object obj, ref Hashtable surrogateDataContracts)
446         {
447             return GetDataContract(((obj == null) ? Globals.TypeOfObject : obj.GetType()), ref surrogateDataContracts);
448         }
449
450         internal DataContract GetDataContract(Type type, ref Hashtable surrogateDataContracts)
451         {
452             return GetDataContract(type.TypeHandle, type, ref surrogateDataContracts);
453         }
454
455         internal DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts)
456         {
457             DataContract dataContract = GetDataContractFromSurrogateSelector(surrogateSelector, Context, typeHandle, type, ref surrogateDataContracts);
458             if (dataContract != null)
459                 return dataContract;
460
461             if (cachedDataContract == null)
462             {
463                 dataContract = DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType);
464                 cachedDataContract = dataContract;
465                 return dataContract;
466             }
467
468             DataContract currentCachedDataContract = cachedDataContract;
469             if (currentCachedDataContract.UnderlyingType.TypeHandle.Equals(typeHandle))
470                 return currentCachedDataContract;
471
472             return DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType);
473         }
474
475         [Fx.Tag.SecurityNote(Critical = "Calls the critical methods of ISurrogateSelector", Safe = "Demands for FullTrust")]
476         [SecuritySafeCritical]
477         [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
478         [MethodImpl(MethodImplOptions.NoInlining)]
479         static ISerializationSurrogate GetSurrogate(Type type, ISurrogateSelector surrogateSelector, StreamingContext context)
480         {
481             ISurrogateSelector surrogateSelectorNotUsed;
482             return surrogateSelector.GetSurrogate(type, context, out surrogateSelectorNotUsed);
483         }
484
485         internal static DataContract GetDataContractFromSurrogateSelector(ISurrogateSelector surrogateSelector, StreamingContext context, RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts)
486         {
487             if (surrogateSelector == null)
488                 return null;
489
490             if (type == null)
491                 type = Type.GetTypeFromHandle(typeHandle);
492             DataContract builtInDataContract = DataContract.GetBuiltInDataContract(type);
493             if (builtInDataContract != null)
494                 return builtInDataContract;
495             if (surrogateDataContracts != null)
496             {
497                 DataContract cachedSurrogateContract = (DataContract)surrogateDataContracts[type];
498                 if (cachedSurrogateContract != null)
499                     return cachedSurrogateContract;
500             }
501             DataContract surrogateContract = null;
502             ISerializationSurrogate surrogate = GetSurrogate(type, surrogateSelector, context);
503             if (surrogate != null)
504                 surrogateContract = new SurrogateDataContract(type, surrogate);
505             else if (type.IsArray)
506             {
507                 Type elementType = type.GetElementType();
508                 DataContract itemContract = GetDataContractFromSurrogateSelector(surrogateSelector, context, elementType.TypeHandle, elementType, ref surrogateDataContracts);
509                 if (itemContract == null)
510                     itemContract = DataContract.GetDataContract(elementType.TypeHandle, elementType, SerializationMode.SharedType);
511                 surrogateContract = new CollectionDataContract(type, itemContract);
512             }
513             if (surrogateContract != null)
514             {
515                 if (surrogateDataContracts == null)
516                     surrogateDataContracts = new Hashtable();
517                 surrogateDataContracts.Add(type, surrogateContract);
518                 return surrogateContract;
519             }
520             return null;
521         }
522
523
524         internal static TypeInformation GetTypeInformation(Type type)
525         {
526             TypeInformation typeInformation = null;
527             object typeInformationObject = typeNameCache[type];
528             if (typeInformationObject == null)
529             {
530                 bool hasTypeForwardedFrom;
531                 string assemblyName = DataContract.GetClrAssemblyName(type, out hasTypeForwardedFrom);
532                 typeInformation = new TypeInformation(DataContract.GetClrTypeFullNameUsingTypeForwardedFromAttribute(type), assemblyName, hasTypeForwardedFrom);
533                 lock (typeNameCache)
534                 {
535                     typeNameCache[type] = typeInformation;
536                 }
537             }
538             else
539             {
540                 typeInformation = (TypeInformation)typeInformationObject;
541             }
542             return typeInformation;
543         }
544
545         static bool IsAssemblyNameForwardingSafe(string originalAssemblyName, string newAssemblyName)
546         {
547             if (originalAssemblyName == newAssemblyName)
548             {
549                 return true;
550             }
551
552             AssemblyName originalAssembly = new AssemblyName(originalAssemblyName);
553             AssemblyName newAssembly = new AssemblyName(newAssemblyName);
554
555             // mscorlib will get loaded by the runtime regardless of its string casing or its public key token,
556             // so setting the assembly name to mscorlib is always unsafe
557             if (string.Equals(newAssembly.Name, Globals.MscorlibAssemblySimpleName, StringComparison.OrdinalIgnoreCase) ||
558                 string.Equals(newAssembly.Name, Globals.MscorlibFileName, StringComparison.OrdinalIgnoreCase))
559             {
560                 return false;
561             }
562
563             return IsPublicKeyTokenForwardingSafe(originalAssembly.GetPublicKeyToken(), newAssembly.GetPublicKeyToken());
564         }
565
566         static bool IsPublicKeyTokenForwardingSafe(byte[] sourceToken, byte[] destinationToken)
567         {
568             if (sourceToken == null || destinationToken == null || sourceToken.Length == 0 || destinationToken.Length == 0 || sourceToken.Length != destinationToken.Length)
569             {
570                 return false;
571             }
572             
573             for (int i = 0; i < sourceToken.Length; i++)
574             {
575                 if (sourceToken[i] != destinationToken[i])
576                 {
577                     return false;
578                 }
579             }
580             return true;
581         }
582     }
583
584 }