Add mobile build support in System.Runtime.Serialization.
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Runtime / Serialization / Json / JsonCollectionDataContract.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Runtime.Serialization.Json
6 {
7     using System.Threading;
8     using System.Xml;
9     using System.Security;
10
11     class JsonCollectionDataContract : JsonDataContract
12     {
13         [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization."
14             + "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
15         [SecurityCritical]
16         JsonCollectionDataContractCriticalHelper helper;
17
18         [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
19             Safe = "Doesn't leak anything.")]
20         [SecuritySafeCritical]
21         public JsonCollectionDataContract(CollectionDataContract traditionalDataContract)
22             : base(new JsonCollectionDataContractCriticalHelper(traditionalDataContract))
23         {
24             this.helper = base.Helper as JsonCollectionDataContractCriticalHelper;
25         }
26
27         internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate
28         {
29             [Fx.Tag.SecurityNote(Critical = "Fetches the critical JsonFormatReaderDelegate property.",
30                 Safe = "JsonFormatReaderDelegate only needs to be protected for write.")]
31             [SecuritySafeCritical]
32             get
33             {
34                 if (helper.JsonFormatReaderDelegate == null)
35                 {
36                     lock (this)
37                     {
38                         if (helper.JsonFormatReaderDelegate == null)
39                         {
40                             if (TraditionalCollectionDataContract.IsReadOnlyContract)
41                             {
42                                 DataContract.ThrowInvalidDataContractException(TraditionalCollectionDataContract.DeserializationExceptionMessage, null /*type*/);
43                             }
44                             JsonFormatCollectionReaderDelegate tempDelegate = new JsonFormatReaderGenerator().GenerateCollectionReader(TraditionalCollectionDataContract);
45                             Thread.MemoryBarrier();
46                             helper.JsonFormatReaderDelegate = tempDelegate;
47                         }
48                     }
49                 }
50                 return helper.JsonFormatReaderDelegate;
51             }
52         }
53
54         internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelegate
55         {
56             [Fx.Tag.SecurityNote(Critical = "Fetches the critical JsonFormatGetOnlyReaderDelegate property.",
57                 Safe = "JsonFormatGetOnlyReaderDelegate only needs to be protected for write; initialized in getter if null.")]
58             [SecuritySafeCritical]
59             get
60             {
61                 if (helper.JsonFormatGetOnlyReaderDelegate == null)
62                 {
63                     lock (this)
64                     {
65                         if (helper.JsonFormatGetOnlyReaderDelegate == null)
66                         {
67                             CollectionKind kind = this.TraditionalCollectionDataContract.Kind;
68                             if (this.TraditionalDataContract.UnderlyingType.IsInterface && (kind == CollectionKind.Enumerable || kind == CollectionKind.Collection || kind == CollectionKind.GenericEnumerable))
69                             {
70                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GetOnlyCollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(this.TraditionalDataContract.UnderlyingType))));
71                             }
72                             if (TraditionalCollectionDataContract.IsReadOnlyContract)
73                             {
74                                 DataContract.ThrowInvalidDataContractException(TraditionalCollectionDataContract.DeserializationExceptionMessage, null /*type*/);
75                             }
76                             JsonFormatGetOnlyCollectionReaderDelegate tempDelegate = new JsonFormatReaderGenerator().GenerateGetOnlyCollectionReader(TraditionalCollectionDataContract);
77                             Thread.MemoryBarrier();
78                             helper.JsonFormatGetOnlyReaderDelegate = tempDelegate;
79                         }
80                     }
81                 }
82                 return helper.JsonFormatGetOnlyReaderDelegate;
83             }
84         }
85
86         internal JsonFormatCollectionWriterDelegate JsonFormatWriterDelegate
87         {
88             [Fx.Tag.SecurityNote(Critical = "Fetches the critical JsonFormatWriterDelegate property.",
89                 Safe = "JsonFormatWriterDelegate only needs to be protected for write.")]
90             [SecuritySafeCritical]
91             get
92             {
93                 if (helper.JsonFormatWriterDelegate == null)
94                 {
95                     lock (this)
96                     {
97                         if (helper.JsonFormatWriterDelegate == null)
98                         {
99                             JsonFormatCollectionWriterDelegate tempDelegate = new JsonFormatWriterGenerator().GenerateCollectionWriter(TraditionalCollectionDataContract);
100                             Thread.MemoryBarrier();
101                             helper.JsonFormatWriterDelegate = tempDelegate;
102                         }
103                     }
104                 }
105                 return helper.JsonFormatWriterDelegate;
106             }
107         }
108
109         CollectionDataContract TraditionalCollectionDataContract
110         {
111             [Fx.Tag.SecurityNote(Critical = "Fetches the critical TraditionalCollectionDataContract property.",
112                 Safe = "TraditionalCollectionDataContract only needs to be protected for write.")]
113             [SecuritySafeCritical]
114             get { return this.helper.TraditionalCollectionDataContract; }
115         }
116
117         public override object ReadJsonValueCore(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context)
118         {
119             jsonReader.Read();
120             object o = null;
121             if (context.IsGetOnlyCollection)
122             {
123                 // IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset. 
124                 context.IsGetOnlyCollection = false;
125                 JsonFormatGetOnlyReaderDelegate(jsonReader, context, XmlDictionaryString.Empty, JsonGlobals.itemDictionaryString, TraditionalCollectionDataContract);
126             }
127             else
128             {
129                 o = JsonFormatReaderDelegate(jsonReader, context, XmlDictionaryString.Empty, JsonGlobals.itemDictionaryString, TraditionalCollectionDataContract);
130             }
131             jsonReader.ReadEndElement();
132             return o;
133         }
134
135         public override void WriteJsonValueCore(XmlWriterDelegator jsonWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, RuntimeTypeHandle declaredTypeHandle)
136         {
137             // IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset. 
138             context.IsGetOnlyCollection = false;
139             JsonFormatWriterDelegate(jsonWriter, obj, context, TraditionalCollectionDataContract);
140         }
141
142         [Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing types."
143             + "Since the data is cached statically, we lock down access to it.")]
144 #if !NO_SECURITY_ATTRIBUTES
145 #pragma warning disable 618 // have not moved to the v4 security model yet
146         [SecurityCritical(SecurityCriticalScope.Everything)]
147 #pragma warning restore 618
148 #endif
149         class JsonCollectionDataContractCriticalHelper : JsonDataContractCriticalHelper
150         {
151             JsonFormatCollectionReaderDelegate jsonFormatReaderDelegate;
152             JsonFormatGetOnlyCollectionReaderDelegate jsonFormatGetOnlyReaderDelegate;
153             JsonFormatCollectionWriterDelegate jsonFormatWriterDelegate;
154             CollectionDataContract traditionalCollectionDataContract;
155
156             public JsonCollectionDataContractCriticalHelper(CollectionDataContract traditionalDataContract)
157                 : base(traditionalDataContract)
158             {
159                 this.traditionalCollectionDataContract = traditionalDataContract;
160             }
161
162             internal JsonFormatCollectionReaderDelegate JsonFormatReaderDelegate
163             {
164                 get { return this.jsonFormatReaderDelegate; }
165                 set { this.jsonFormatReaderDelegate = value; }
166             }
167
168             internal JsonFormatGetOnlyCollectionReaderDelegate JsonFormatGetOnlyReaderDelegate
169             {
170                 get { return this.jsonFormatGetOnlyReaderDelegate; }
171                 set { this.jsonFormatGetOnlyReaderDelegate = value; }
172             }
173
174             internal JsonFormatCollectionWriterDelegate JsonFormatWriterDelegate
175             {
176                 get { return this.jsonFormatWriterDelegate; }
177                 set { this.jsonFormatWriterDelegate = value; }
178             }
179
180             internal CollectionDataContract TraditionalCollectionDataContract
181             {
182                 get { return this.traditionalCollectionDataContract; }
183             }
184
185         }
186     }
187 }